diff --git a/res/values/strings.xml b/res/values/strings.xml index b49557ec291..00cdf40bd6f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2195,6 +2195,8 @@ Wi\u2011Fi turned on Connected to %1$s + + Connecting to %1$s Connecting\u2026 diff --git a/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java b/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java index 9f0023aa15c..3b75ebf420e 100644 --- a/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java +++ b/src/com/android/settings/homepage/contextualcards/ContextualCardsFragment.java @@ -40,7 +40,6 @@ import com.android.settings.core.InstrumentedFragment; import com.android.settings.homepage.contextualcards.slices.BluetoothUpdateWorker; import com.android.settings.homepage.contextualcards.slices.SwipeDismissalDelegate; import com.android.settings.overlay.FeatureFactory; -import com.android.settings.wifi.slice.ContextualWifiScanWorker; public class ContextualCardsFragment extends InstrumentedFragment implements FocusRecyclerView.FocusListener { @@ -80,7 +79,6 @@ public class ContextualCardsFragment extends InstrumentedFragment implements super.onStart(); registerScreenOffReceiver(); registerKeyEventReceiver(); - ContextualWifiScanWorker.newVisibleUiSession(); mContextualCardManager.loadContextualCards(LoaderManager.getInstance(this), sRestartLoaderNeeded); sRestartLoaderNeeded = false; diff --git a/src/com/android/settings/wifi/AddNetworkFragment.java b/src/com/android/settings/wifi/AddNetworkFragment.java index 7e17e380e79..31dc21fea29 100644 --- a/src/com/android/settings/wifi/AddNetworkFragment.java +++ b/src/com/android/settings/wifi/AddNetworkFragment.java @@ -32,6 +32,7 @@ import androidx.annotation.VisibleForTesting; import com.android.settings.R; import com.android.settings.core.InstrumentedFragment; +import com.android.settings.wifi.dpp.WifiDppQrCodeScannerFragment; import com.android.settings.wifi.dpp.WifiDppUtils; /** @@ -116,7 +117,7 @@ public class AddNetworkFragment extends InstrumentedFragment implements WifiConf } final WifiConfiguration config = data.getParcelableExtra( - WifiDialogActivity.KEY_WIFI_CONFIGURATION); + WifiDppQrCodeScannerFragment.KEY_WIFI_CONFIGURATION); successfullyFinish(config); } } diff --git a/src/com/android/settings/wifi/WifiDialogActivity.java b/src/com/android/settings/wifi/WifiDialogActivity.java index 77827867630..b25d13f7520 100644 --- a/src/com/android/settings/wifi/WifiDialogActivity.java +++ b/src/com/android/settings/wifi/WifiDialogActivity.java @@ -16,51 +16,56 @@ package com.android.settings.wifi; -import android.app.Activity; import android.content.DialogInterface; import android.content.Intent; -import android.net.NetworkInfo; +import android.net.ConnectivityManager; +import android.net.NetworkScoreManager; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; -import android.net.wifi.WifiManager.ActionListener; import android.os.Bundle; -import android.util.Log; - -import androidx.annotation.VisibleForTesting; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Process; +import android.os.SimpleClock; +import android.os.SystemClock; import com.android.settings.R; import com.android.settings.SetupWizardUtils; import com.android.settings.wifi.dpp.WifiDppUtils; -import com.android.settingslib.wifi.AccessPoint; +import com.android.settingslib.core.lifecycle.ObservableActivity; +import com.android.wifitrackerlib.NetworkDetailsTracker; +import com.android.wifitrackerlib.WifiEntry; import com.google.android.setupcompat.util.WizardManagerHelper; -public class WifiDialogActivity extends Activity implements WifiDialog.WifiDialogListener, - DialogInterface.OnDismissListener { +import java.time.Clock; +import java.time.ZoneOffset; + +/** + * The activity shows a CONNECT_MODE Wi-fi editor dialog. + */ +public class WifiDialogActivity extends ObservableActivity implements + WifiDialog2.WifiDialog2Listener, DialogInterface.OnDismissListener { private static final String TAG = "WifiDialogActivity"; - public static final String KEY_ACCESS_POINT_STATE = "access_point_state"; - - /** - * Boolean extra indicating whether this activity should connect to an access point on the - * caller's behalf. If this is set to false, the caller should check - * {@link #KEY_WIFI_CONFIGURATION} in the result data and save that using - * {@link WifiManager#connect(WifiConfiguration, ActionListener)}. Default is true. - */ - @VisibleForTesting - static final String KEY_CONNECT_FOR_CALLER = "connect_for_caller"; - - public static final String KEY_WIFI_CONFIGURATION = "wifi_configuration"; + public static final String KEY_CHOSEN_WIFIENTRY_KEY = "key_chosen_wifientry_key"; private static final int RESULT_CONNECTED = RESULT_FIRST_USER; private static final int RESULT_FORGET = RESULT_FIRST_USER + 1; private static final int REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER = 0; - private WifiDialog mDialog; + // Max age of tracked WifiEntries. + private static final long MAX_SCAN_AGE_MILLIS = 15_000; + // Interval between initiating NetworkDetailsTracker scans. + private static final long SCAN_INTERVAL_MILLIS = 10_000; + private WifiDialog2 mDialog; private Intent mIntent; + private NetworkDetailsTracker mNetworkDetailsTracker; + private HandlerThread mWorkerThread; @Override protected void onCreate(Bundle savedInstanceState) { @@ -71,18 +76,43 @@ public class WifiDialogActivity extends Activity implements WifiDialog.WifiDialo super.onCreate(savedInstanceState); - final Bundle accessPointState = mIntent.getBundleExtra(KEY_ACCESS_POINT_STATE); - AccessPoint accessPoint = null; - if (accessPointState != null) { - accessPoint = new AccessPoint(this, accessPointState); + mWorkerThread = new HandlerThread( + TAG + "{" + Integer.toHexString(System.identityHashCode(this)) + "}", + Process.THREAD_PRIORITY_BACKGROUND); + mWorkerThread.start(); + final Clock elapsedRealtimeClock = new SimpleClock(ZoneOffset.UTC) { + @Override + public long millis() { + return SystemClock.elapsedRealtime(); + } + }; + mNetworkDetailsTracker = NetworkDetailsTracker.createNetworkDetailsTracker( + getLifecycle(), + this, + getSystemService(WifiManager.class), + getSystemService(ConnectivityManager.class), + getSystemService(NetworkScoreManager.class), + new Handler(Looper.getMainLooper()), + mWorkerThread.getThreadHandler(), + elapsedRealtimeClock, + MAX_SCAN_AGE_MILLIS, + SCAN_INTERVAL_MILLIS, + mIntent.getStringExtra(KEY_CHOSEN_WIFIENTRY_KEY)); + } + + @Override + protected void onStart() { + super.onStart(); + if (mDialog != null) { + return; } if (WizardManagerHelper.isAnySetupWizard(getIntent())) { - mDialog = WifiDialog.createModal(this, this, accessPoint, - WifiConfigUiBase.MODE_CONNECT, R.style.SuwAlertDialogThemeCompat_Light); + mDialog = WifiDialog2.createModal(this, this, mNetworkDetailsTracker.getWifiEntry(), + WifiConfigUiBase2.MODE_CONNECT, R.style.SuwAlertDialogThemeCompat_Light); } else { - mDialog = WifiDialog.createModal( - this, this, accessPoint, WifiConfigUiBase.MODE_CONNECT); + mDialog = WifiDialog2.createModal(this, this, mNetworkDetailsTracker.getWifiEntry(), + WifiConfigUiBase2.MODE_CONNECT); } mDialog.show(); mDialog.setOnDismissListener(this); @@ -90,82 +120,44 @@ public class WifiDialogActivity extends Activity implements WifiDialog.WifiDialo @Override public void finish() { - super.finish(); overridePendingTransition(0, 0); + + super.finish(); } @Override public void onDestroy() { - super.onDestroy(); if (mDialog != null && mDialog.isShowing()) { mDialog.dismiss(); mDialog = null; } + mWorkerThread.quit(); + + super.onDestroy(); } @Override - public void onForget(WifiDialog dialog) { - final WifiManager wifiManager = getSystemService(WifiManager.class); - final AccessPoint accessPoint = dialog.getController().getAccessPoint(); - if (accessPoint != null) { - if (!accessPoint.isSaved()) { - if (accessPoint.getNetworkInfo() != null && - accessPoint.getNetworkInfo().getState() != NetworkInfo.State.DISCONNECTED) { - // Network is active but has no network ID - must be ephemeral. - wifiManager.disableEphemeralNetwork( - AccessPoint.convertToQuotedString(accessPoint.getSsidStr())); - } else { - // Should not happen, but a monkey seems to trigger it - Log.e(TAG, "Failed to forget invalid network " + accessPoint.getConfig()); - } - } else { - wifiManager.forget(accessPoint.getConfig().networkId, null /* listener */); - } + public void onForget(WifiDialog2 dialog) { + final WifiEntry wifiEntry = dialog.getController().getWifiEntry(); + if (wifiEntry != null && wifiEntry.canForget()) { + wifiEntry.forget(null /* callback */); } - Intent resultData = new Intent(); - if (accessPoint != null) { - Bundle accessPointState = new Bundle(); - accessPoint.saveWifiState(accessPointState); - resultData.putExtra(KEY_ACCESS_POINT_STATE, accessPointState); - } setResult(RESULT_FORGET); finish(); } @Override - public void onSubmit(WifiDialog dialog) { + public void onSubmit(WifiDialog2 dialog) { + final WifiEntry wifiEntry = dialog.getController().getWifiEntry(); final WifiConfiguration config = dialog.getController().getConfig(); - final AccessPoint accessPoint = dialog.getController().getAccessPoint(); - final WifiManager wifiManager = getSystemService(WifiManager.class); - - if (getIntent().getBooleanExtra(KEY_CONNECT_FOR_CALLER, true)) { - if (config == null) { - if (accessPoint != null && accessPoint.isSaved()) { - wifiManager.connect(accessPoint.getConfig(), null /* listener */); - } - } else { - wifiManager.save(config, null /* listener */); - if (accessPoint != null) { - // accessPoint is null for "Add network" - NetworkInfo networkInfo = accessPoint.getNetworkInfo(); - if (networkInfo == null || !networkInfo.isConnected()) { - wifiManager.connect(config, null /* listener */); - } - } - } + if (config == null && wifiEntry != null && wifiEntry.canConnect()) { + wifiEntry.connect(null /* callback */); + } else { + getSystemService(WifiManager.class).connect(config, null /* listener */); } - Intent resultData = new Intent(); - if (accessPoint != null) { - Bundle accessPointState = new Bundle(); - accessPoint.saveWifiState(accessPointState); - resultData.putExtra(KEY_ACCESS_POINT_STATE, accessPointState); - } - if (config != null) { - resultData.putExtra(KEY_WIFI_CONFIGURATION, config); - } - setResult(RESULT_CONNECTED, resultData); + setResult(RESULT_CONNECTED); finish(); } @@ -176,7 +168,7 @@ public class WifiDialogActivity extends Activity implements WifiDialog.WifiDialo } @Override - public void onScan(WifiDialog dialog, String ssid) { + public void onScan(WifiDialog2 dialog, String ssid) { Intent intent = WifiDppUtils.getEnrolleeQrCodeScannerIntent(ssid); WizardManagerHelper.copyWizardManagerExtras(mIntent, intent); diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java index accef12364f..cee3ccdeb08 100644 --- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java +++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java @@ -57,7 +57,6 @@ import androidx.annotation.VisibleForTesting; import androidx.lifecycle.ViewModelProviders; import com.android.settings.R; -import com.android.settings.wifi.WifiDialogActivity; import com.android.settings.wifi.qrcode.QrCamera; import com.android.settings.wifi.qrcode.QrDecorateView; import com.android.wifitrackerlib.WifiEntry; @@ -91,7 +90,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl // Key for Bundle usage private static final String KEY_IS_CONFIGURATOR_MODE = "key_is_configurator_mode"; private static final String KEY_LATEST_ERROR_CODE = "key_latest_error_code"; - private static final String KEY_WIFI_CONFIGURATION = "key_wifi_configuration"; + public static final String KEY_WIFI_CONFIGURATION = "key_wifi_configuration"; private static final int ARG_RESTART_CAMERA = 1; @@ -689,8 +688,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl @Override public void onSuccess() { final Intent resultIntent = new Intent(); - resultIntent.putExtra(WifiDialogActivity.KEY_WIFI_CONFIGURATION, - mEnrolleeWifiConfiguration); + resultIntent.putExtra(KEY_WIFI_CONFIGURATION, mEnrolleeWifiConfiguration); final Activity hostActivity = getActivity(); hostActivity.setResult(Activity.RESULT_OK, resultIntent); diff --git a/src/com/android/settings/wifi/slice/ConnectToWifiHandler.java b/src/com/android/settings/wifi/slice/ConnectToWifiHandler.java index 5c92d81da22..779a57e40f3 100644 --- a/src/com/android/settings/wifi/slice/ConnectToWifiHandler.java +++ b/src/com/android/settings/wifi/slice/ConnectToWifiHandler.java @@ -19,61 +19,74 @@ package com.android.settings.wifi.slice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.net.ConnectivityManager; -import android.net.Network; -import android.net.wifi.WifiManager; -import android.os.Bundle; +import android.text.TextUtils; +import android.widget.Toast; import androidx.annotation.VisibleForTesting; -import com.android.settings.wifi.WifiConnectListener; +import com.android.settings.R; +import com.android.settings.slices.SliceBackgroundWorker; import com.android.settings.wifi.WifiDialogActivity; -import com.android.settings.wifi.WifiUtils; -import com.android.settingslib.wifi.AccessPoint; +import com.android.wifitrackerlib.WifiEntry; +import com.android.wifitrackerlib.WifiEntry.ConnectCallback; /** * This receiver helps connect to Wi-Fi network */ public class ConnectToWifiHandler extends BroadcastReceiver { + static final String KEY_CHOSEN_WIFIENTRY_KEY = "key_chosen_wifientry_key"; + static final String KEY_WIFI_SLICE_URI = "key_wifi_slice_uri"; + @Override public void onReceive(Context context, Intent intent) { if (context == null || intent == null) { return; } - - final Network network = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK); - final Bundle accessPointState = intent.getBundleExtra( - WifiDialogActivity.KEY_ACCESS_POINT_STATE); - - if (network != null) { - WifiScanWorker.clearClickedWifi(); - final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class); - // start captive portal app to sign in to network - cm.startCaptivePortalApp(network); - } else if (accessPointState != null) { - connect(context, new AccessPoint(context, accessPointState)); + final String key = intent.getStringExtra(KEY_CHOSEN_WIFIENTRY_KEY); + if (TextUtils.isEmpty(key)) { + return; } + if (intent.getParcelableExtra(KEY_WIFI_SLICE_URI) == null) { + return; + } + final WifiScanWorker worker = getWifiScanWorker(intent); + if (worker == null) { + return; + } + final WifiEntry wifiEntry = worker.getWifiEntry(key); + if (wifiEntry == null) { + return; + } + wifiEntry.connect(new WifiEntryConnectCallback(context, wifiEntry)); } @VisibleForTesting - void connect(Context context, AccessPoint accessPoint) { - ContextualWifiScanWorker.saveSession(); - WifiScanWorker.saveClickedWifi(accessPoint); + WifiScanWorker getWifiScanWorker(Intent intent) { + return SliceBackgroundWorker.getInstance(intent.getParcelableExtra(KEY_WIFI_SLICE_URI)); + } - final WifiConnectListener connectListener = new WifiConnectListener(context); - switch (WifiUtils.getConnectingType(accessPoint)) { - case WifiUtils.CONNECT_TYPE_OSU_PROVISION: - accessPoint.startOsuProvisioning(connectListener); - break; + @VisibleForTesting + static class WifiEntryConnectCallback implements WifiEntry.ConnectCallback { + final Context mContext; + final WifiEntry mWifiEntry; - case WifiUtils.CONNECT_TYPE_OPEN_NETWORK: - accessPoint.generateOpenNetworkConfig(); + WifiEntryConnectCallback(Context context, WifiEntry connectWifiEntry) { + mContext = context; + mWifiEntry = connectWifiEntry; + } - case WifiUtils.CONNECT_TYPE_SAVED_NETWORK: - final WifiManager wifiManager = context.getSystemService(WifiManager.class); - wifiManager.connect(accessPoint.getConfig(), connectListener); - break; + @Override + public void onConnectResult(@ConnectStatus int status) { + if (status == ConnectCallback.CONNECT_STATUS_FAILURE_NO_CONFIG) { + final Intent intent = new Intent(mContext, WifiDialogActivity.class) + .putExtra(WifiDialogActivity.KEY_CHOSEN_WIFIENTRY_KEY, mWifiEntry.getKey()); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + } else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) { + Toast.makeText(mContext, R.string.wifi_failed_connect_message, + Toast.LENGTH_SHORT).show(); + } } } } diff --git a/src/com/android/settings/wifi/slice/ContextualWifiScanWorker.java b/src/com/android/settings/wifi/slice/ContextualWifiScanWorker.java index 616c92fb33a..aa73a179d39 100644 --- a/src/com/android/settings/wifi/slice/ContextualWifiScanWorker.java +++ b/src/com/android/settings/wifi/slice/ContextualWifiScanWorker.java @@ -18,7 +18,6 @@ package com.android.settings.wifi.slice; import android.content.Context; import android.net.Uri; -import android.os.SystemClock; import com.android.settings.slices.SliceBackgroundWorker; @@ -27,44 +26,12 @@ import com.android.settings.slices.SliceBackgroundWorker; */ public class ContextualWifiScanWorker extends WifiScanWorker { - private static long sVisibleUiSessionToken; - private static long sActiveSession; - public ContextualWifiScanWorker(Context context, Uri uri) { super(context, uri); } - /** - * Starts a new visible UI session for the purpose of automatically starting captive portal. - * - * A visible UI session is defined as a duration of time when a UI screen is visible to user. - * Going to a sub-page and coming out breaks the continuation, leaving the page and coming back - * breaks it too. - */ - public static void newVisibleUiSession() { - sVisibleUiSessionToken = SystemClock.elapsedRealtime(); - } - - static void saveSession() { - sActiveSession = sVisibleUiSessionToken; - } - - @Override - protected void clearClickedWifiOnSliceUnpinned() { - // Do nothing for contextual Wi-Fi slice - } - - @Override - protected boolean isSessionValid() { - if (sVisibleUiSessionToken != sActiveSession) { - clearClickedWifi(); - return false; - } - return true; - } - @Override protected int getApRowCount() { return ContextualWifiSlice.getApRowCount(); } -} \ No newline at end of file +} diff --git a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java index ea9a7452202..4806573bf1e 100644 --- a/src/com/android/settings/wifi/slice/ContextualWifiSlice.java +++ b/src/com/android/settings/wifi/slice/ContextualWifiSlice.java @@ -18,10 +18,8 @@ package com.android.settings.wifi.slice; import android.content.Context; import android.graphics.drawable.Drawable; +import android.net.ConnectivityManager; import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; -import android.net.NetworkInfo.State; import android.net.Uri; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; @@ -37,7 +35,7 @@ import com.android.settings.Utils; import com.android.settings.overlay.FeatureFactory; import com.android.settings.slices.CustomSliceRegistry; import com.android.settings.slices.CustomSliceable; -import com.android.settingslib.wifi.AccessPoint; +import com.android.wifitrackerlib.WifiEntry; /** * {@link CustomSliceable} for Wi-Fi, used by contextual homepage. @@ -52,8 +50,12 @@ public class ContextualWifiSlice extends WifiSlice { @VisibleForTesting static boolean sApRowCollapsed; + private final ConnectivityManager mConnectivityManager; + public ContextualWifiSlice(Context context) { super(context); + + mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); } @Override @@ -84,16 +86,17 @@ public class ContextualWifiSlice extends WifiSlice { } @Override - protected ListBuilder.RowBuilder getHeaderRow(boolean isWifiEnabled, AccessPoint accessPoint) { - final ListBuilder.RowBuilder builder = super.getHeaderRow(isWifiEnabled, accessPoint); - builder.setTitleItem(getHeaderIcon(isWifiEnabled, accessPoint), ListBuilder.ICON_IMAGE); + protected ListBuilder.RowBuilder getHeaderRow(boolean isWifiEnabled, + WifiSliceItem wifiSliceItem) { + final ListBuilder.RowBuilder builder = super.getHeaderRow(isWifiEnabled, wifiSliceItem); + builder.setTitleItem(getHeaderIcon(isWifiEnabled, wifiSliceItem), ListBuilder.ICON_IMAGE); if (sApRowCollapsed) { - builder.setSubtitle(getSubtitle(accessPoint)); + builder.setSubtitle(getHeaderSubtitle(wifiSliceItem)); } return builder; } - private IconCompat getHeaderIcon(boolean isWifiEnabled, AccessPoint accessPoint) { + private IconCompat getHeaderIcon(boolean isWifiEnabled, WifiSliceItem wifiSliceItem) { final Drawable drawable; final int tint; if (!isWifiEnabled) { @@ -103,7 +106,8 @@ public class ContextualWifiSlice extends WifiSlice { } else { // get icon of medium signal strength drawable = mContext.getDrawable(com.android.settingslib.Utils.getWifiIconResource(2)); - if (isNetworkConnected(accessPoint)) { + if (wifiSliceItem != null + && wifiSliceItem.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED) { tint = Utils.getColorAccentDefaultColor(mContext); } else { tint = Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal); @@ -113,49 +117,16 @@ public class ContextualWifiSlice extends WifiSlice { return Utils.createIconWithDrawable(drawable); } - private boolean isNetworkConnected(AccessPoint accessPoint) { - if (accessPoint == null) { - return false; - } - - final NetworkInfo networkInfo = accessPoint.getNetworkInfo(); - if (networkInfo == null) { - return false; - } - - return networkInfo.getState() == State.CONNECTED; - } - - private CharSequence getSubtitle(AccessPoint accessPoint) { - if (isCaptivePortal()) { - final int id = mContext.getResources() - .getIdentifier("network_available_sign_in", "string", "android"); - return mContext.getText(id); - } - - if (accessPoint == null) { + private CharSequence getHeaderSubtitle(WifiSliceItem wifiSliceItem) { + if (wifiSliceItem == null + || wifiSliceItem.getConnectedState() == WifiEntry.CONNECTED_STATE_DISCONNECTED) { return mContext.getText(R.string.disconnected); } - - final NetworkInfo networkInfo = accessPoint.getNetworkInfo(); - if (networkInfo == null) { - return mContext.getText(R.string.disconnected); + if (wifiSliceItem.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTING) { + return mContext.getString(R.string.wifi_connecting_to_message, + wifiSliceItem.getTitle()); } - - final State state = networkInfo.getState(); - DetailedState detailedState; - if (state == State.CONNECTING) { - detailedState = DetailedState.CONNECTING; - } else if (state == State.CONNECTED) { - detailedState = DetailedState.CONNECTED; - } else { - detailedState = networkInfo.getDetailedState(); - } - - final String[] formats = mContext.getResources().getStringArray( - R.array.wifi_status_with_ssid); - final int index = detailedState.ordinal(); - return String.format(formats[index], accessPoint.getTitle()); + return mContext.getString(R.string.wifi_connected_to_message, wifiSliceItem.getTitle()); } private boolean hasWorkingNetwork() { diff --git a/src/com/android/settings/wifi/slice/WifiScanWorker.java b/src/com/android/settings/wifi/slice/WifiScanWorker.java index 9d0f8210624..631faac18ef 100644 --- a/src/com/android/settings/wifi/slice/WifiScanWorker.java +++ b/src/com/android/settings/wifi/slice/WifiScanWorker.java @@ -16,243 +16,187 @@ package com.android.settings.wifi.slice; -import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; -import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; -import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; -import static android.net.NetworkCapabilities.TRANSPORT_WIFI; - import static com.android.settings.wifi.slice.WifiSlice.DEFAULT_EXPANDED_ROW_COUNT; import android.content.Context; -import android.content.Intent; import android.net.ConnectivityManager; -import android.net.ConnectivityManager.NetworkCallback; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; +import android.net.NetworkScoreManager; import android.net.Uri; -import android.net.wifi.WifiInfo; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.UserHandle; +import android.net.wifi.WifiManager; +import android.os.HandlerThread; +import android.os.Process; +import android.os.SimpleClock; +import android.os.SystemClock; import android.text.TextUtils; -import android.util.Log; import androidx.annotation.VisibleForTesting; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LifecycleRegistry; -import com.android.internal.util.Preconditions; import com.android.settings.slices.SliceBackgroundWorker; -import com.android.settingslib.wifi.AccessPoint; -import com.android.settingslib.wifi.WifiTracker; +import com.android.settingslib.utils.ThreadUtils; +import com.android.wifitrackerlib.WifiEntry; +import com.android.wifitrackerlib.WifiEntry.WifiEntryCallback; +import com.android.wifitrackerlib.WifiPickerTracker; +import java.time.Clock; +import java.time.ZoneOffset; import java.util.ArrayList; import java.util.List; /** * {@link SliceBackgroundWorker} for Wi-Fi, used by {@link WifiSlice}. */ -public class WifiScanWorker extends SliceBackgroundWorker implements - WifiTracker.WifiListener { +public class WifiScanWorker extends SliceBackgroundWorker implements + WifiPickerTracker.WifiPickerTrackerCallback, LifecycleOwner, WifiEntryCallback { private static final String TAG = "WifiScanWorker"; + // Max age of tracked WifiEntries. + private static final long MAX_SCAN_AGE_MILLIS = 15_000; + // Interval between initiating WifiPickerTracker scans. + private static final long SCAN_INTERVAL_MILLIS = 10_000; + @VisibleForTesting - WifiNetworkCallback mNetworkCallback; - - private final Context mContext; - private final ConnectivityManager mConnectivityManager; - private final WifiTracker mWifiTracker; - - private static String sClickedWifiSsid; + final LifecycleRegistry mLifecycleRegistry; + @VisibleForTesting + WifiPickerTracker mWifiPickerTracker; + // Worker thread used for WifiPickerTracker work + private final HandlerThread mWorkerThread; public WifiScanWorker(Context context, Uri uri) { super(context, uri); - mContext = context; - mConnectivityManager = context.getSystemService(ConnectivityManager.class); - mWifiTracker = new WifiTracker(mContext, this /* wifiListener */, - true /* includeSaved */, true /* includeScans */); + + mLifecycleRegistry = new LifecycleRegistry(this); + + mWorkerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND); + mWorkerThread.start(); + final Clock elapsedRealtimeClock = new SimpleClock(ZoneOffset.UTC) { + @Override + public long millis() { + return SystemClock.elapsedRealtime(); + } + }; + mWifiPickerTracker = new WifiPickerTracker(getLifecycle(), context, + context.getSystemService(WifiManager.class), + context.getSystemService(ConnectivityManager.class), + context.getSystemService(NetworkScoreManager.class), + ThreadUtils.getUiThreadHandler(), + mWorkerThread.getThreadHandler(), + elapsedRealtimeClock, + MAX_SCAN_AGE_MILLIS, + SCAN_INTERVAL_MILLIS, + this); + + mLifecycleRegistry.markState(Lifecycle.State.INITIALIZED); + mLifecycleRegistry.markState(Lifecycle.State.CREATED); } @Override protected void onSlicePinned() { - mWifiTracker.onStart(); - onAccessPointsChanged(); + mLifecycleRegistry.markState(Lifecycle.State.STARTED); + mLifecycleRegistry.markState(Lifecycle.State.RESUMED); + updateResults(); } @Override protected void onSliceUnpinned() { - mWifiTracker.onStop(); - unregisterNetworkCallback(); - clearClickedWifiOnSliceUnpinned(); + mLifecycleRegistry.markState(Lifecycle.State.STARTED); + mLifecycleRegistry.markState(Lifecycle.State.CREATED); } @Override public void close() { - mWifiTracker.onDestroy(); + mLifecycleRegistry.markState(Lifecycle.State.DESTROYED); + mWorkerThread.quit(); } @Override - public void onWifiStateChanged(int state) { + public Lifecycle getLifecycle() { + return mLifecycleRegistry; + } + + /** Called when the state of Wifi has changed. */ + @Override + public void onWifiStateChanged() { + updateResults(); + } + + /** + * Update the results when data changes + */ + @Override + public void onWifiEntriesChanged() { + updateResults(); + } + + /** + * Indicates the state of the WifiEntry has changed and clients may retrieve updates through + * the WifiEntry getter methods. + */ + @Override + public void onUpdated() { notifySliceChange(); } - @Override - public void onConnectedChanged() { - } - - @Override - public void onAccessPointsChanged() { - // in case state has changed - if (!mWifiTracker.getManager().isWifiEnabled()) { - updateResults(null); - return; - } - // AccessPoints are sorted by the WifiTracker - final List accessPoints = mWifiTracker.getAccessPoints(); - final List resultList = new ArrayList<>(); - final int apRowCount = getApRowCount(); - for (AccessPoint ap : accessPoints) { - if (ap.isReachable()) { - resultList.add(clone(ap)); - if (resultList.size() >= apRowCount) { - break; - } - } - } - updateResults(resultList); - } - protected int getApRowCount() { return DEFAULT_EXPANDED_ROW_COUNT; } - private AccessPoint clone(AccessPoint accessPoint) { - final Bundle savedState = new Bundle(); - accessPoint.saveWifiState(savedState); - return new AccessPoint(mContext, savedState); + @Override + public void onNumSavedSubscriptionsChanged() { + // Do nothing. } @Override - protected boolean areListsTheSame(List a, List b) { - if (!a.equals(b)) { - return false; - } + public void onNumSavedNetworksChanged() { + // Do nothing. + } - // compare access point states one by one - final int listSize = a.size(); - for (int i = 0; i < listSize; i++) { - if (a.get(i).getDetailedState() != b.get(i).getDetailedState()) { - return false; + /** + * To get the WifiEntry of key. + */ + public WifiEntry getWifiEntry(String key) { + // Get specified WifiEntry. + WifiEntry keyWifiEntry = null; + final WifiEntry connectedWifiEntry = mWifiPickerTracker.getConnectedWifiEntry(); + if (connectedWifiEntry != null && TextUtils.equals(key, connectedWifiEntry.getKey())) { + keyWifiEntry = connectedWifiEntry; + } else { + for (WifiEntry wifiEntry : mWifiPickerTracker.getWifiEntries()) { + if (TextUtils.equals(key, wifiEntry.getKey())) { + keyWifiEntry = wifiEntry; + break; + } } } - return true; + return keyWifiEntry; } - static void saveClickedWifi(AccessPoint accessPoint) { - sClickedWifiSsid = accessPoint.getSsidStr(); - } - - static void clearClickedWifi() { - sClickedWifiSsid = null; - } - - static boolean isWifiClicked(WifiInfo info) { - final String ssid = WifiInfo.sanitizeSsid(info.getSSID()); - return !TextUtils.isEmpty(ssid) && TextUtils.equals(ssid, sClickedWifiSsid); - } - - protected void clearClickedWifiOnSliceUnpinned() { - clearClickedWifi(); - } - - protected boolean isSessionValid() { - return true; - } - - public void registerNetworkCallback(Network wifiNetwork) { - if (wifiNetwork == null) { + @VisibleForTesting + void updateResults() { + if (mWifiPickerTracker.getWifiState() != WifiManager.WIFI_STATE_ENABLED + || mLifecycleRegistry.getCurrentState() != Lifecycle.State.RESUMED) { + super.updateResults(null); return; } - if (mNetworkCallback != null && mNetworkCallback.isSameNetwork(wifiNetwork)) { - return; + final List resultList = new ArrayList<>(); + final WifiEntry connectedWifiEntry = mWifiPickerTracker.getConnectedWifiEntry(); + if (connectedWifiEntry != null) { + connectedWifiEntry.setListener(this); + resultList.add(new WifiSliceItem(getContext(), connectedWifiEntry)); } - - unregisterNetworkCallback(); - - mNetworkCallback = new WifiNetworkCallback(wifiNetwork); - mConnectivityManager.registerNetworkCallback( - new NetworkRequest.Builder() - .clearCapabilities() - .addTransportType(TRANSPORT_WIFI) - .build(), - mNetworkCallback, - new Handler(Looper.getMainLooper())); - } - - public void unregisterNetworkCallback() { - if (mNetworkCallback != null) { - try { - mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); - } catch (RuntimeException e) { - Log.e(TAG, "Unregistering CaptivePortalNetworkCallback failed.", e); + for (WifiEntry wifiEntry : mWifiPickerTracker.getWifiEntries()) { + if (resultList.size() >= getApRowCount()) { + break; } - mNetworkCallback = null; - } - } - - class WifiNetworkCallback extends NetworkCallback { - - private final Network mNetwork; - private boolean mIsCaptivePortal; - private boolean mHasPartialConnectivity; - private boolean mIsValidated; - - WifiNetworkCallback(Network network) { - mNetwork = Preconditions.checkNotNull(network); - } - - @Override - public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { - if (!isSameNetwork(network)) { - return; - } - - final boolean prevIsCaptivePortal = mIsCaptivePortal; - final boolean prevHasPartialConnectivity = mHasPartialConnectivity; - final boolean prevIsValidated = mIsValidated; - - mIsCaptivePortal = nc.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL); - mHasPartialConnectivity = nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY); - mIsValidated = nc.hasCapability(NET_CAPABILITY_VALIDATED); - - if (prevIsCaptivePortal == mIsCaptivePortal - && prevHasPartialConnectivity == mHasPartialConnectivity - && prevIsValidated == mIsValidated) { - return; - } - - notifySliceChange(); - - // Automatically start captive portal - if (!prevIsCaptivePortal && mIsCaptivePortal - && isWifiClicked(mWifiTracker.getManager().getConnectionInfo()) - && isSessionValid()) { - final Intent intent = new Intent(mContext, ConnectToWifiHandler.class) - .putExtra(ConnectivityManager.EXTRA_NETWORK, network) - .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); - // Sending a broadcast in the system process needs to specify a user - mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); + if (wifiEntry.getLevel() != WifiEntry.WIFI_LEVEL_UNREACHABLE) { + wifiEntry.setListener(this); + resultList.add(new WifiSliceItem(getContext(), wifiEntry)); } } - - /** - * Returns true if the supplied network is not null and is the same as the originally - * supplied value. - */ - public boolean isSameNetwork(Network network) { - return mNetwork.equals(network); - } + super.updateResults(resultList); } } diff --git a/src/com/android/settings/wifi/slice/WifiSlice.java b/src/com/android/settings/wifi/slice/WifiSlice.java index a489b05e2e4..324d68c870e 100644 --- a/src/com/android/settings/wifi/slice/WifiSlice.java +++ b/src/com/android/settings/wifi/slice/WifiSlice.java @@ -29,9 +29,6 @@ import android.content.Intent; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; -import android.net.ConnectivityManager; -import android.net.NetworkCapabilities; -import android.net.NetworkInfo; import android.net.Uri; import android.net.wifi.WifiManager; import android.os.Bundle; @@ -52,9 +49,8 @@ import com.android.settings.slices.SliceBackgroundWorker; import com.android.settings.slices.SliceBuilderUtils; import com.android.settings.wifi.WifiDialogActivity; import com.android.settings.wifi.WifiSettings; -import com.android.settings.wifi.WifiUtils; -import com.android.settings.wifi.details.WifiNetworkDetailsFragment; -import com.android.settingslib.wifi.AccessPoint; +import com.android.settings.wifi.details2.WifiNetworkDetailsFragment2; +import com.android.wifitrackerlib.WifiEntry; import java.util.Arrays; import java.util.List; @@ -71,12 +67,10 @@ public class WifiSlice implements CustomSliceable { protected final Context mContext; protected final WifiManager mWifiManager; - protected final ConnectivityManager mConnectivityManager; public WifiSlice(Context context) { mContext = context; mWifiManager = mContext.getSystemService(WifiManager.class); - mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); } @Override @@ -87,17 +81,16 @@ public class WifiSlice implements CustomSliceable { @Override public Slice getSlice() { final boolean isWifiEnabled = isWifiEnabled(); - ListBuilder listBuilder = getListBuilder(isWifiEnabled, null /* accessPoint */); + ListBuilder listBuilder = getListBuilder(isWifiEnabled, null /* wifiSliceItem */); if (!isWifiEnabled) { - WifiScanWorker.clearClickedWifi(); return listBuilder.build(); } final WifiScanWorker worker = SliceBackgroundWorker.getInstance(getUri()); - final List apList = worker != null ? worker.getResults() : null; + final List apList = worker != null ? worker.getResults() : null; final int apCount = apList == null ? 0 : apList.size(); - final boolean isFirstApActive = apCount > 0 && apList.get(0).isActive(); - handleNetworkCallback(worker, isFirstApActive); + final boolean isFirstApActive = apCount > 0 + && apList.get(0).getConnectedState() != WifiEntry.CONNECTED_STATE_DISCONNECTED; if (isFirstApActive) { // refresh header subtext @@ -112,7 +105,7 @@ public class WifiSlice implements CustomSliceable { final CharSequence placeholder = mContext.getText(R.string.summary_placeholder); for (int i = 0; i < DEFAULT_EXPANDED_ROW_COUNT; i++) { if (i < apCount) { - listBuilder.addRow(getAccessPointRow(apList.get(i))); + listBuilder.addRow(getWifiSliceItemRow(apList.get(i))); } else if (i == apCount) { listBuilder.addRow(getLoadingRow(placeholder)); } else { @@ -124,22 +117,12 @@ public class WifiSlice implements CustomSliceable { return listBuilder.build(); } - private void handleNetworkCallback(WifiScanWorker worker, boolean isFirstApActive) { - if (worker == null) { - return; - } - if (isFirstApActive) { - worker.registerNetworkCallback(mWifiManager.getCurrentNetwork()); - } else { - worker.unregisterNetworkCallback(); - } - } - protected boolean isApRowCollapsed() { return false; } - protected ListBuilder.RowBuilder getHeaderRow(boolean isWifiEnabled, AccessPoint accessPoint) { + protected ListBuilder.RowBuilder getHeaderRow(boolean isWifiEnabled, + WifiSliceItem wifiSliceItem) { final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_settings_wireless); final String title = mContext.getString(R.string.wifi_settings); @@ -152,115 +135,90 @@ public class WifiSlice implements CustomSliceable { .setPrimaryAction(primarySliceAction); } - private ListBuilder getListBuilder(boolean isWifiEnabled, AccessPoint accessPoint) { + private ListBuilder getListBuilder(boolean isWifiEnabled, WifiSliceItem wifiSliceItem) { final PendingIntent toggleAction = getBroadcastIntent(mContext); final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction, null /* actionTitle */, isWifiEnabled); final ListBuilder builder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY) .setAccentColor(COLOR_NOT_TINTED) .setKeywords(getKeywords()) - .addRow(getHeaderRow(isWifiEnabled, accessPoint)) + .addRow(getHeaderRow(isWifiEnabled, wifiSliceItem)) .addAction(toggleSliceAction); return builder; } - private ListBuilder.RowBuilder getAccessPointRow(AccessPoint accessPoint) { - final boolean isCaptivePortal = accessPoint.isActive() && isCaptivePortal(); - final CharSequence title = accessPoint.getTitle(); - final CharSequence summary = getAccessPointSummary(accessPoint, isCaptivePortal); - final IconCompat levelIcon = getAccessPointLevelIcon(accessPoint); + private ListBuilder.RowBuilder getWifiSliceItemRow(WifiSliceItem wifiSliceItem) { + final CharSequence title = wifiSliceItem.getTitle(); + final IconCompat levelIcon = getWifiSliceItemLevelIcon(wifiSliceItem); final ListBuilder.RowBuilder rowBuilder = new ListBuilder.RowBuilder() .setTitleItem(levelIcon, ListBuilder.ICON_IMAGE) .setTitle(title) - .setSubtitle(summary) - .setPrimaryAction(getAccessPointAction(accessPoint, isCaptivePortal, levelIcon, - title)); + .setSubtitle(wifiSliceItem.getSummary()) + .setContentDescription(wifiSliceItem.getContentDescription()) + .setPrimaryAction(getWifiEntryAction(wifiSliceItem, levelIcon, title)); - if (isCaptivePortal) { - rowBuilder.addEndItem(getCaptivePortalEndAction(accessPoint, title)); - } else { - final IconCompat endIcon = getEndIcon(accessPoint); - if (endIcon != null) { - rowBuilder.addEndItem(endIcon, ListBuilder.ICON_IMAGE); - } + final IconCompat endIcon = getEndIcon(wifiSliceItem); + if (endIcon != null) { + rowBuilder.addEndItem(endIcon, ListBuilder.ICON_IMAGE); } return rowBuilder; } - private CharSequence getAccessPointSummary(AccessPoint accessPoint, boolean isCaptivePortal) { - if (isCaptivePortal) { - return mContext.getText(R.string.wifi_tap_to_sign_in); - } - - final CharSequence summary = accessPoint.getSettingsSummary(); - return TextUtils.isEmpty(summary) ? mContext.getText(R.string.disconnected) : summary; - } - - private IconCompat getAccessPointLevelIcon(AccessPoint accessPoint) { + private IconCompat getWifiSliceItemLevelIcon(WifiSliceItem wifiSliceItem) { final @ColorInt int tint; - if (accessPoint.isActive()) { - final NetworkInfo.State state = accessPoint.getNetworkInfo().getState(); - if (state == NetworkInfo.State.CONNECTED) { - tint = Utils.getColorAccentDefaultColor(mContext); - } else { // connecting - tint = Utils.getDisabled(mContext, Utils.getColorAttrDefaultColor(mContext, - android.R.attr.colorControlNormal)); - } - } else { + if (wifiSliceItem.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED) { + tint = Utils.getColorAccentDefaultColor(mContext); + } else if (wifiSliceItem.getConnectedState() == WifiEntry.CONNECTED_STATE_DISCONNECTED) { tint = Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal); + } else { + tint = Utils.getDisabled(mContext, Utils.getColorAttrDefaultColor(mContext, + android.R.attr.colorControlNormal)); } final Drawable drawable = mContext.getDrawable( - com.android.settingslib.Utils.getWifiIconResource(accessPoint.getLevel())); + com.android.settingslib.Utils.getWifiIconResource(wifiSliceItem.getLevel())); drawable.setTint(tint); return Utils.createIconWithDrawable(drawable); } - private IconCompat getEndIcon(AccessPoint accessPoint) { - if (accessPoint.isActive()) { + private IconCompat getEndIcon(WifiSliceItem wifiSliceItem) { + if (wifiSliceItem.getConnectedState() != WifiEntry.CONNECTED_STATE_DISCONNECTED) { return null; - } else if (accessPoint.getSecurity() != AccessPoint.SECURITY_NONE) { + } + + if (wifiSliceItem.getSecurity() != WifiEntry.SECURITY_NONE) { return IconCompat.createWithResource(mContext, R.drawable.ic_friction_lock_closed); - } else if (accessPoint.isMetered()) { - return IconCompat.createWithResource(mContext, R.drawable.ic_friction_money); } return null; } - private SliceAction getCaptivePortalEndAction(AccessPoint accessPoint, CharSequence title) { - return getAccessPointAction(accessPoint, false /* isCaptivePortal */, - IconCompat.createWithResource(mContext, R.drawable.ic_settings_accent), title); - } + private SliceAction getWifiEntryAction(WifiSliceItem wifiSliceItem, IconCompat icon, + CharSequence title) { + final int requestCode = wifiSliceItem.getKey().hashCode(); - private SliceAction getAccessPointAction(AccessPoint accessPoint, boolean isCaptivePortal, - IconCompat icon, CharSequence title) { - final int requestCode = accessPoint.hashCode(); - if (isCaptivePortal) { - final Intent intent = new Intent(mContext, ConnectToWifiHandler.class) - .putExtra(ConnectivityManager.EXTRA_NETWORK, mWifiManager.getCurrentNetwork()); - return getBroadcastAction(requestCode, intent, icon, title); - } - - final Bundle extras = new Bundle(); - accessPoint.saveWifiState(extras); - - if (accessPoint.isActive()) { + if (wifiSliceItem.getConnectedState() != WifiEntry.CONNECTED_STATE_DISCONNECTED) { + final Bundle bundle = new Bundle(); + bundle.putString(WifiNetworkDetailsFragment2.KEY_CHOSEN_WIFIENTRY_KEY, + wifiSliceItem.getKey()); final Intent intent = new SubSettingLauncher(mContext) .setTitleRes(R.string.pref_title_network_details) - .setDestination(WifiNetworkDetailsFragment.class.getName()) - .setArguments(extras) + .setDestination(WifiNetworkDetailsFragment2.class.getName()) + .setArguments(bundle) .setSourceMetricsCategory(SettingsEnums.WIFI) .toIntent(); return getActivityAction(requestCode, intent, icon, title); - } else if (WifiUtils.getConnectingType(accessPoint) != WifiUtils.CONNECT_TYPE_OTHERS) { - final Intent intent = new Intent(mContext, ConnectToWifiHandler.class) - .putExtra(WifiDialogActivity.KEY_ACCESS_POINT_STATE, extras); - return getBroadcastAction(requestCode, intent, icon, title); - } else { + } + + if (wifiSliceItem.shouldEditBeforeConnect()) { final Intent intent = new Intent(mContext, WifiDialogActivity.class) - .putExtra(WifiDialogActivity.KEY_ACCESS_POINT_STATE, extras); + .putExtra(WifiDialogActivity.KEY_CHOSEN_WIFIENTRY_KEY, wifiSliceItem.getKey()); return getActivityAction(requestCode, intent, icon, title); } + + final Intent intent = new Intent(mContext, ConnectToWifiHandler.class) + .putExtra(ConnectToWifiHandler.KEY_CHOSEN_WIFIENTRY_KEY, wifiSliceItem.getKey()) + .putExtra(ConnectToWifiHandler.KEY_WIFI_SLICE_URI, getUri()); + return getBroadcastAction(requestCode, intent, icon, title); } private SliceAction getActivityAction(int requestCode, Intent intent, IconCompat icon, @@ -291,12 +249,6 @@ public class WifiSlice implements CustomSliceable { .setSubtitle(title); } - protected boolean isCaptivePortal() { - final NetworkCapabilities nc = mConnectivityManager.getNetworkCapabilities( - mWifiManager.getCurrentNetwork()); - return WifiUtils.canSignIntoNetwork(nc); - } - /** * Update the current wifi status to the boolean value keyed by * {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}. diff --git a/src/com/android/settings/wifi/slice/WifiSliceItem.java b/src/com/android/settings/wifi/slice/WifiSliceItem.java new file mode 100644 index 00000000000..7a0f0d73a20 --- /dev/null +++ b/src/com/android/settings/wifi/slice/WifiSliceItem.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.wifi.slice; + +import android.content.Context; +import android.text.TextUtils; + +import com.android.settingslib.R; +import com.android.wifitrackerlib.WifiEntry; + +/** + * The data set which is needed by a Wi-Fi Slice, it collects necessary data from {@link WifiEntry} + * and provides similar getter methods for corresponding data. + */ +public class WifiSliceItem { + + private final Context mContext; + private final String mKey; + private final String mTitle; + private final int mSecurity; + private final int mConnectedState; + private final int mLevel; + private final boolean mShouldEditBeforeConnect; + private final String mSummary; + + // These values must be kept within [WifiEntry.WIFI_LEVEL_MIN, WifiEntry.WIFI_LEVEL_MAX] + private static final int[] WIFI_CONNECTION_STRENGTH = { + R.string.accessibility_no_wifi, + R.string.accessibility_wifi_one_bar, + R.string.accessibility_wifi_two_bars, + R.string.accessibility_wifi_three_bars, + R.string.accessibility_wifi_signal_full + }; + + public WifiSliceItem(Context context, WifiEntry wifiEntry) { + mContext = context; + mKey = wifiEntry.getKey(); + mTitle = wifiEntry.getTitle(); + mSecurity = wifiEntry.getSecurity(); + mConnectedState = wifiEntry.getConnectedState(); + mLevel = wifiEntry.getLevel(); + mShouldEditBeforeConnect = wifiEntry.shouldEditBeforeConnect(); + mSummary = wifiEntry.getSummary(false /* concise */); + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof WifiSliceItem)) { + return false; + } + + final WifiSliceItem otherItem = (WifiSliceItem) other; + if (!TextUtils.equals(getKey(), otherItem.getKey())) { + return false; + } + if (getConnectedState() != otherItem.getConnectedState()) { + return false; + } + if (getLevel() != otherItem.getLevel()) { + return false; + } + if (!TextUtils.equals(getSummary(), otherItem.getSummary())) { + return false; + } + return true; + } + + public String getKey() { + return mKey; + } + + public String getTitle() { + return mTitle; + } + + public int getSecurity() { + return mSecurity; + } + + public int getConnectedState() { + return mConnectedState; + } + + public int getLevel() { + return mLevel; + } + + /** + * In Wi-Fi picker, when users click a saved network, it will connect to the Wi-Fi network. + * However, for some special cases, Wi-Fi picker should show Wi-Fi editor UI for users to edit + * security or password before connecting. Or users will always get connection fail results. + */ + public boolean shouldEditBeforeConnect() { + return mShouldEditBeforeConnect; + } + + /** + * Returns a 'NOT' concise summary, this is different from WifiEntry#getSummary(). + */ + public String getSummary() { + return mSummary; + } + + /** + * This method has similar code as WifiEntryPreference#buildContentDescription(). + * TODO(b/154191825): Adds WifiEntry#getContentDescription() to replace the duplicate code. + */ + public CharSequence getContentDescription() { + CharSequence contentDescription = mTitle; + if (!TextUtils.isEmpty(mSummary)) { + contentDescription = TextUtils.concat(contentDescription, ",", mSummary); + } + if (mLevel >= 0 && mLevel < WIFI_CONNECTION_STRENGTH.length) { + contentDescription = TextUtils.concat(contentDescription, ",", + mContext.getString(WIFI_CONNECTION_STRENGTH[mLevel])); + } + return TextUtils.concat(contentDescription, ",", mSecurity == WifiEntry.SECURITY_NONE + ? mContext.getString(R.string.accessibility_wifi_security_type_none) + : mContext.getString(R.string.accessibility_wifi_security_type_secured)); + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java index 80db53e7be1..ea57bf7e89d 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java @@ -18,6 +18,7 @@ package com.android.settings.testutils.shadow; import static org.robolectric.RuntimeEnvironment.application; +import android.net.wifi.ScanResult; import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; @@ -81,6 +82,11 @@ public class ShadowWifiManager extends org.robolectric.shadows.ShadowWifiManager return false; } + @Implementation + protected List getScanResults() { + return new ArrayList(); + } + public static ShadowWifiManager get() { return Shadow.extract(application.getSystemService(WifiManager.class)); } diff --git a/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java b/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java index 41d1bbe4f38..12f7c67b4bb 100644 --- a/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java +++ b/tests/robotests/src/com/android/settings/wifi/WifiDialogActivityTest.java @@ -50,7 +50,7 @@ public class WifiDialogActivityTest { private static final String AP1_SSID = "\"ap1\""; @Mock - private WifiConfigController mController; + private WifiConfigController2 mController; @Before public void setUp() { @@ -63,8 +63,12 @@ public class WifiDialogActivityTest { @Test public void onSubmit_shouldConnectToNetwork() { - WifiDialogActivity activity = Robolectric.setupActivity(WifiDialogActivity.class); - WifiDialog dialog = (WifiDialog) ShadowAlertDialogCompat.getLatestAlertDialog(); + WifiDialogActivity activity = + Robolectric.buildActivity(WifiDialogActivity.class, + new Intent().putExtra(WifiDialogActivity.KEY_CHOSEN_WIFIENTRY_KEY, + "StandardWifiEntry:OpenNetwork,0")) + .setup().get(); + WifiDialog2 dialog = (WifiDialog2) ShadowAlertDialogCompat.getLatestAlertDialog(); assertThat(dialog).isNotNull(); ReflectionHelpers.setField(dialog, "mController", mController); @@ -74,35 +78,18 @@ public class WifiDialogActivityTest { assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP1_SSID); } - @Test - public void onSubmit_whenConnectForCallerIsFalse_shouldNotConnectToNetwork() { - WifiDialogActivity activity = - Robolectric.buildActivity( - WifiDialogActivity.class, - new Intent().putExtra(WifiDialogActivity.KEY_CONNECT_FOR_CALLER, false)) - .setup().get(); - WifiDialog dialog = (WifiDialog) ShadowAlertDialogCompat.getLatestAlertDialog(); - - assertThat(dialog).isNotNull(); - - ReflectionHelpers.setField(dialog, "mController", mController); - - activity.onSubmit(dialog); - - assertThat(ShadowWifiManager.get().savedWifiConfig).isNull(); - } - @Test public void onSubmit_whenLaunchInSetupFlow_shouldBeLightThemeForWifiDialog() { WifiDialogActivity activity = Robolectric.buildActivity( WifiDialogActivity.class, new Intent() - .putExtra(WifiDialogActivity.KEY_CONNECT_FOR_CALLER, false) .putExtra(WizardManagerHelper.EXTRA_IS_FIRST_RUN, true) - .putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true)) + .putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true) + .putExtra(WifiDialogActivity.KEY_CHOSEN_WIFIENTRY_KEY, + "StandardWifiEntry:OpenNetwork,0")) .setup().get(); - WifiDialog dialog = (WifiDialog) ShadowAlertDialogCompat.getLatestAlertDialog(); + WifiDialog2 dialog = (WifiDialog2) ShadowAlertDialogCompat.getLatestAlertDialog(); assertThat(dialog).isNotNull(); diff --git a/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java b/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java index ac1384f8756..829ec8fc4dd 100644 --- a/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/slice/ConnectToWifiHandlerTest.java @@ -26,95 +26,69 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; -import android.net.wifi.WifiManager; +import android.content.Intent; -import com.android.settings.testutils.shadow.ShadowWifiManager; -import com.android.settingslib.wifi.AccessPoint; +import com.android.settings.wifi.WifiDialogActivity; +import com.android.wifitrackerlib.WifiEntry; +import com.android.wifitrackerlib.WifiEntry.ConnectCallback; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) -@Config(shadows = ShadowWifiManager.class) public class ConnectToWifiHandlerTest { private static final String AP_SSID = "\"ap\""; private Context mContext; private ConnectToWifiHandler mHandler; - private WifiConfiguration mWifiConfig; @Mock - private AccessPoint mAccessPoint; + private WifiScanWorker mWifiScanWorker; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; - mHandler = new ConnectToWifiHandler(); - mWifiConfig = spy(new WifiConfiguration()); - mWifiConfig.SSID = AP_SSID; - doReturn(mWifiConfig).when(mAccessPoint).getConfig(); + mContext = spy(RuntimeEnvironment.application); + mHandler = spy(new ConnectToWifiHandler()); + doReturn(mWifiScanWorker).when(mHandler).getWifiScanWorker(any()); } @Test - public void connect_shouldConnectToUnsavedOpenNetwork() { - when(mAccessPoint.isSaved()).thenReturn(false); - when(mAccessPoint.getSecurity()).thenReturn(AccessPoint.SECURITY_NONE); + public void onReceive_nonNullKeyAndUri_shouldConnectWifintry() { + final Intent intent = new Intent(); + final String key = "key"; + intent.putExtra(ConnectToWifiHandler.KEY_CHOSEN_WIFIENTRY_KEY, key); + intent.putExtra(ConnectToWifiHandler.KEY_WIFI_SLICE_URI, + com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI); + final WifiEntry wifiEntry = mock(WifiEntry.class); + when(mWifiScanWorker.getWifiEntry(key)).thenReturn(wifiEntry); - mHandler.connect(mContext, mAccessPoint); + mHandler.onReceive(mContext, intent); - assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP_SSID); + verify(wifiEntry).connect(any()); } @Test - public void connect_shouldStartOsuProvisioning() { - when(mAccessPoint.isSaved()).thenReturn(false); - when(mAccessPoint.isOsuProvider()).thenReturn(true); + public void onConnectResult_failNoConfig_shouldStartActivity() { + final String key = "key"; + final WifiEntry wifiEntry = mock(WifiEntry.class); + when(wifiEntry.getKey()).thenReturn(key); + final ConnectToWifiHandler.WifiEntryConnectCallback callback = + spy(new ConnectToWifiHandler.WifiEntryConnectCallback(mContext, wifiEntry)); - mHandler.connect(mContext, mAccessPoint); + callback.onConnectResult(ConnectCallback.CONNECT_STATUS_FAILURE_NO_CONFIG); - verify(mAccessPoint).startOsuProvisioning(any(WifiManager.ActionListener.class)); - } - - - @Test - public void connect_shouldConnectWithPasspointProvider() { - when(mAccessPoint.isSaved()).thenReturn(false); - when(mAccessPoint.isPasspoint()).thenReturn(true); - - mHandler.connect(mContext, mAccessPoint); - - assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP_SSID); - } - - @Test - public void connect_shouldConnectToSavedSecuredNetwork() { - when(mAccessPoint.isSaved()).thenReturn(true); - when(mAccessPoint.getSecurity()).thenReturn(AccessPoint.SECURITY_PSK); - final NetworkSelectionStatus status = mock(NetworkSelectionStatus.class); - when(status.hasEverConnected()).thenReturn(true); - when(mWifiConfig.getNetworkSelectionStatus()).thenReturn(status); - - mHandler.connect(mContext, mAccessPoint); - - assertThat(ShadowWifiManager.get().savedWifiConfig.SSID).isEqualTo(AP_SSID); - } - - @Test - public void connect_shouldNotConnectToUnsavedSecuredNetwork() { - when(mAccessPoint.isSaved()).thenReturn(false); - when(mAccessPoint.getSecurity()).thenReturn(AccessPoint.SECURITY_PSK); - - mHandler.connect(mContext, mAccessPoint); - - assertThat(ShadowWifiManager.get().savedWifiConfig).isNull(); + final ArgumentCaptor argument = ArgumentCaptor.forClass(Intent.class); + verify(mContext).startActivity(argument.capture()); + assertThat(argument.getValue().getStringExtra(WifiDialogActivity.KEY_CHOSEN_WIFIENTRY_KEY)) + .isEqualTo(key); + assertThat(argument.getValue().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) + .isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK); } } diff --git a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiScanWorkerTest.java b/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiScanWorkerTest.java deleted file mode 100644 index 0e525207caa..00000000000 --- a/tests/robotests/src/com/android/settings/wifi/slice/ContextualWifiScanWorkerTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.settings.wifi.slice; - -import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_WIFI_SLICE_URI; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - -import android.content.Context; -import android.content.Intent; -import android.net.ConnectivityManager; -import android.net.ConnectivityManager.NetworkCallback; -import android.net.Network; -import android.net.wifi.WifiManager; -import android.os.UserHandle; - -import com.android.settings.testutils.shadow.ShadowWifiManager; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -@RunWith(RobolectricTestRunner.class) -@Config(shadows = { - ShadowWifiManager.class, - WifiScanWorkerTest.ShadowWifiTracker.class, -}) -public class ContextualWifiScanWorkerTest { - - private Context mContext; - private WifiManager mWifiManager; - private ConnectivityManager mConnectivityManager; - private ContextualWifiScanWorker mWifiScanWorker; - private ConnectToWifiHandler mConnectToWifiHandler; - - @Before - public void setUp() { - mContext = spy(RuntimeEnvironment.application); - mWifiManager = mContext.getSystemService(WifiManager.class); - mWifiManager.setWifiEnabled(true); - - mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); - mWifiScanWorker = new ContextualWifiScanWorker(mContext, CONTEXTUAL_WIFI_SLICE_URI); - mConnectToWifiHandler = new ConnectToWifiHandler(); - } - - @After - public void tearDown() { - mWifiScanWorker.clearClickedWifi(); - } - - @Test - public void NetworkCallback_onCapabilitiesChanged_sliceIsUnpinned_shouldSendBroadcast() { - final Intent intent = WifiScanWorkerTest.getIntentWithAccessPoint("ap1"); - WifiScanWorkerTest.setConnectionInfoSSID("ap1"); - final Network network = mConnectivityManager.getActiveNetwork(); - mWifiScanWorker.registerNetworkCallback(network); - final NetworkCallback callback = mWifiScanWorker.mNetworkCallback; - - mWifiScanWorker.onSlicePinned(); - mConnectToWifiHandler.onReceive(mContext, intent); - mWifiScanWorker.onSliceUnpinned(); - callback.onCapabilitiesChanged(network, - WifiSliceTest.makeCaptivePortalNetworkCapabilities()); - - verify(mContext).sendBroadcastAsUser(any(Intent.class), eq(UserHandle.CURRENT)); - } - - @Test - public void NetworkCallback_onCapabilitiesChanged_newSession_shouldNotSendBroadcast() { - final Intent intent = WifiScanWorkerTest.getIntentWithAccessPoint("ap1"); - WifiScanWorkerTest.setConnectionInfoSSID("ap1"); - final Network network = mConnectivityManager.getActiveNetwork(); - mWifiScanWorker.registerNetworkCallback(network); - - mConnectToWifiHandler.onReceive(mContext, intent); - ContextualWifiScanWorker.newVisibleUiSession(); - mWifiScanWorker.mNetworkCallback.onCapabilitiesChanged(network, - WifiSliceTest.makeCaptivePortalNetworkCapabilities()); - - verify(mContext, never()).sendBroadcastAsUser(any(Intent.class), eq(UserHandle.CURRENT)); - } -} diff --git a/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java index 33195438fe0..395048c3c64 100644 --- a/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiScanWorkerTest.java @@ -17,216 +17,89 @@ package com.android.settings.wifi.slice; import static com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI; -import static com.android.settings.wifi.WifiDialogActivity.KEY_ACCESS_POINT_STATE; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.net.ConnectivityManager; -import android.net.ConnectivityManager.NetworkCallback; -import android.net.Network; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.os.Bundle; -import android.os.UserHandle; +import androidx.lifecycle.Lifecycle; -import com.android.settings.slices.ShadowSliceBackgroundWorker; -import com.android.settings.testutils.shadow.ShadowWifiManager; -import com.android.settingslib.wifi.AccessPoint; -import com.android.settingslib.wifi.WifiTracker; +import com.android.wifitrackerlib.WifiEntry; +import com.android.wifitrackerlib.WifiPickerTracker; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.shadows.ShadowNetworkInfo; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; @RunWith(RobolectricTestRunner.class) -@Config(shadows = {ShadowSliceBackgroundWorker.class, ShadowWifiManager.class, - WifiScanWorkerTest.ShadowWifiTracker.class}) public class WifiScanWorkerTest { - private Context mContext; - private ContentResolver mResolver; - private WifiManager mWifiManager; - private ConnectivityManager mConnectivityManager; private WifiScanWorker mWifiScanWorker; - private ConnectToWifiHandler mConnectToWifiHandler; + @Mock + WifiPickerTracker mWifiPickerTracker; @Before public void setUp() { - mContext = spy(RuntimeEnvironment.application); - mResolver = mock(ContentResolver.class); - doReturn(mResolver).when(mContext).getContentResolver(); - mWifiManager = mContext.getSystemService(WifiManager.class); - mWifiManager.setWifiEnabled(true); + MockitoAnnotations.initMocks(this); - mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); - mWifiScanWorker = new WifiScanWorker(mContext, WIFI_SLICE_URI); - mConnectToWifiHandler = new ConnectToWifiHandler(); - } - - @After - public void tearDown() { - mWifiScanWorker.clearClickedWifi(); + mWifiScanWorker = new WifiScanWorker(RuntimeEnvironment.application, WIFI_SLICE_URI); + mWifiScanWorker.mWifiPickerTracker = mWifiPickerTracker; } @Test - public void onWifiStateChanged_shouldNotifyChange() { - mWifiScanWorker.onWifiStateChanged(WifiManager.WIFI_STATE_DISABLED); - - verify(mResolver).notifyChange(WIFI_SLICE_URI, null); + public void onConstructor_shouldBeInCreatedState() { + assertThat(mWifiScanWorker.getLifecycle().getCurrentState()) + .isEqualTo(Lifecycle.State.CREATED); } @Test - public void AccessPointList_sameState_shouldBeTheSame() { - final AccessPoint ap1 = createAccessPoint(DetailedState.CONNECTED); - final AccessPoint ap2 = createAccessPoint(DetailedState.CONNECTED); - - assertThat(mWifiScanWorker.areListsTheSame(Arrays.asList(ap1), Arrays.asList(ap2))) - .isTrue(); - } - - @Test - public void AccessPointList_differentState_shouldBeDifferent() { - final AccessPoint ap1 = createAccessPoint(DetailedState.CONNECTING); - final AccessPoint ap2 = createAccessPoint(DetailedState.CONNECTED); - - assertThat(mWifiScanWorker.areListsTheSame(Arrays.asList(ap1), Arrays.asList(ap2))) - .isFalse(); - } - - @Test - public void AccessPointList_differentListLength_shouldBeDifferent() { - final AccessPoint ap1 = createAccessPoint(DetailedState.CONNECTED); - final AccessPoint ap2 = createAccessPoint(DetailedState.CONNECTED); - final List list = new ArrayList<>(); - list.add(ap1); - list.add(ap2); - - assertThat(mWifiScanWorker.areListsTheSame(list, Arrays.asList(ap1))).isFalse(); - } - - @Test - public void NetworkCallback_onCapabilitiesChanged_shouldNotifyChange() { - final Network network = mConnectivityManager.getActiveNetwork(); - mWifiScanWorker.registerNetworkCallback(network); - - mWifiScanWorker.mNetworkCallback.onCapabilitiesChanged(network, - WifiSliceTest.makeCaptivePortalNetworkCapabilities()); - - verify(mResolver).notifyChange(WIFI_SLICE_URI, null); - } - - @Test - public void NetworkCallback_onCapabilitiesChanged_isClickedWifi_shouldSendBroadcast() { - final Intent intent = getIntentWithAccessPoint("ap1"); - setConnectionInfoSSID("ap1"); - final Network network = mConnectivityManager.getActiveNetwork(); - mWifiScanWorker.registerNetworkCallback(network); - - mConnectToWifiHandler.onReceive(mContext, intent); - mWifiScanWorker.mNetworkCallback.onCapabilitiesChanged(network, - WifiSliceTest.makeCaptivePortalNetworkCapabilities()); - - verify(mContext).sendBroadcastAsUser(any(Intent.class), eq(UserHandle.CURRENT)); - } - - @Test - public void NetworkCallback_onCapabilitiesChanged_isNotClickedWifi_shouldNotSendBroadcast() { - final Intent intent = getIntentWithAccessPoint("ap1"); - setConnectionInfoSSID("ap2"); - final Network network = mConnectivityManager.getActiveNetwork(); - mWifiScanWorker.registerNetworkCallback(network); - - mConnectToWifiHandler.onReceive(mContext, intent); - mWifiScanWorker.mNetworkCallback.onCapabilitiesChanged(network, - WifiSliceTest.makeCaptivePortalNetworkCapabilities()); - - verify(mContext, never()).sendBroadcastAsUser(any(Intent.class), eq(UserHandle.CURRENT)); - } - - @Test - public void NetworkCallback_onCapabilitiesChanged_neverClickWifi_shouldNotSendBroadcast() { - setConnectionInfoSSID("ap1"); - final Network network = mConnectivityManager.getActiveNetwork(); - mWifiScanWorker.registerNetworkCallback(network); - - mWifiScanWorker.mNetworkCallback.onCapabilitiesChanged(network, - WifiSliceTest.makeCaptivePortalNetworkCapabilities()); - - verify(mContext, never()).sendBroadcastAsUser(any(Intent.class), eq(UserHandle.CURRENT)); - } - - @Test - public void NetworkCallback_onCapabilitiesChanged_sliceIsUnpinned_shouldNotSendBroadcast() { - final Intent intent = getIntentWithAccessPoint("ap1"); - setConnectionInfoSSID("ap1"); - final Network network = mConnectivityManager.getActiveNetwork(); - mWifiScanWorker.registerNetworkCallback(network); - final NetworkCallback callback = mWifiScanWorker.mNetworkCallback; - + public void onSlicePinned_shouldBeInResumedState() { mWifiScanWorker.onSlicePinned(); - mConnectToWifiHandler.onReceive(mContext, intent); + + assertThat(mWifiScanWorker.getLifecycle().getCurrentState()) + .isEqualTo(Lifecycle.State.RESUMED); + } + + @Test + public void onSliceUnpinned_shouldBeInCreatedState() { mWifiScanWorker.onSliceUnpinned(); - callback.onCapabilitiesChanged(network, - WifiSliceTest.makeCaptivePortalNetworkCapabilities()); - verify(mContext, never()).sendBroadcastAsUser(any(Intent.class), eq(UserHandle.CURRENT)); + assertThat(mWifiScanWorker.getLifecycle().getCurrentState()) + .isEqualTo(Lifecycle.State.CREATED); } - static Intent getIntentWithAccessPoint(String ssid) { - final Bundle savedState = new Bundle(); - savedState.putString("key_ssid", ssid); - return new Intent().putExtra(KEY_ACCESS_POINT_STATE, savedState); + @Test + public void close_shouldBeInDestroyedState() { + mWifiScanWorker.close(); + + assertThat(mWifiScanWorker.getLifecycle().getCurrentState()) + .isEqualTo(Lifecycle.State.DESTROYED); } - static void setConnectionInfoSSID(String ssid) { - final WifiInfo wifiInfo = mock(WifiInfo.class); - when(wifiInfo.getSSID()).thenReturn(ssid); - ShadowWifiManager.get().setConnectionInfo(wifiInfo); + @Test + public void getWifiEntry_connectedWifiKey_shouldGetConnectedWifi() { + final String key = "key"; + final WifiEntry connectedWifiEntry = mock(WifiEntry.class); + when(connectedWifiEntry.getKey()).thenReturn(key); + when(mWifiPickerTracker.getConnectedWifiEntry()).thenReturn(connectedWifiEntry); + + assertThat(mWifiScanWorker.getWifiEntry(key)).isEqualTo(connectedWifiEntry); } - private AccessPoint createAccessPoint(String ssid, DetailedState detailedState) { - final NetworkInfo info = ShadowNetworkInfo.newInstance(detailedState, 1 /* type */, - 0 /*subType */, true /* isAvailable */, true /* isConnected */); - final Bundle savedState = new Bundle(); - savedState.putString("key_ssid", ssid); - savedState.putParcelable("key_networkinfo", info); - return new AccessPoint(mContext, savedState); - } + @Test + public void getWifiEntry_reachableWifiKey_shouldGetReachableWifi() { + final String key = "key"; + final WifiEntry reachableWifiEntry = mock(WifiEntry.class); + when(reachableWifiEntry.getKey()).thenReturn(key); + when(mWifiPickerTracker.getWifiEntries()).thenReturn(Arrays.asList(reachableWifiEntry)); - private AccessPoint createAccessPoint(DetailedState detailedState) { - return createAccessPoint("ap", detailedState); - } - - @Implements(WifiTracker.class) - public static class ShadowWifiTracker { - @Implementation - public void onStart() { - // do nothing - } + assertThat(mWifiScanWorker.getWifiEntry(key)).isEqualTo(reachableWifiEntry); } } diff --git a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java index ad74a326c83..5431540028d 100644 --- a/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java +++ b/tests/robotests/src/com/android/settings/wifi/slice/WifiSliceTest.java @@ -23,17 +23,14 @@ import static com.android.settings.wifi.slice.WifiSlice.DEFAULT_EXPANDED_ROW_COU import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; -import android.net.ConnectivityManager; -import android.net.NetworkCapabilities; -import android.net.NetworkInfo; import android.net.Uri; import android.net.wifi.WifiManager; @@ -49,7 +46,8 @@ import androidx.slice.widget.SliceLiveData; import com.android.settings.R; import com.android.settings.slices.SliceBackgroundWorker; import com.android.settings.testutils.SliceTester; -import com.android.settingslib.wifi.AccessPoint; +import com.android.wifitrackerlib.WifiEntry; +import com.android.wifitrackerlib.WifiEntry.ConnectedState; import org.junit.Before; import org.junit.Test; @@ -74,7 +72,6 @@ public class WifiSliceTest { private Context mContext; private ContentResolver mResolver; private WifiManager mWifiManager; - private ConnectivityManager mConnectivityManager; private WifiSlice mWifiSlice; @Before @@ -88,9 +85,6 @@ public class WifiSliceTest { SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); mWifiManager.setWifiEnabled(true); - mConnectivityManager = spy(mContext.getSystemService(ConnectivityManager.class)); - doReturn(mConnectivityManager).when(mContext).getSystemService(ConnectivityManager.class); - mWifiSlice = new WifiSlice(mContext); } @@ -138,33 +132,42 @@ public class WifiSliceTest { mContext.getString(R.string.wifi_empty_list_wifi_on)); } - private AccessPoint createAccessPoint(String name, boolean active, boolean reachable) { - final AccessPoint accessPoint = mock(AccessPoint.class); - doReturn(name).when(accessPoint).getTitle(); - doReturn(active).when(accessPoint).isActive(); - doReturn(reachable).when(accessPoint).isReachable(); - if (active) { - final NetworkInfo networkInfo = mock(NetworkInfo.class); - doReturn(networkInfo).when(accessPoint).getNetworkInfo(); - doReturn(NetworkInfo.State.CONNECTED).when(networkInfo).getState(); - } - return accessPoint; + private WifiSliceItem createWifiSliceItem(String title, @ConnectedState int connectedState) { + final WifiEntry wifiEntry = mock(WifiEntry.class); + when(wifiEntry.getTitle()).thenReturn(title); + when(wifiEntry.getKey()).thenReturn("key"); + when(wifiEntry.getConnectedState()).thenReturn(connectedState); + when(wifiEntry.getLevel()).thenReturn(WifiEntry.WIFI_LEVEL_MAX); + return new WifiSliceItem(mContext, wifiEntry); } - private void setWorkerResults(AccessPoint... accessPoints) { - final ArrayList results = new ArrayList<>(); - for (AccessPoint ap : accessPoints) { - results.add(ap); + private void setWorkerResults(WifiSliceItem... wifiSliceItems) { + final ArrayList results = new ArrayList<>(); + for (WifiSliceItem wifiSliceItem : wifiSliceItems) { + results.add(wifiSliceItem); } final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance(mWifiSlice.getUri()); doReturn(results).when(worker).getResults(); } @Test - public void getWifiSlice_noReachableAp_shouldReturnLoadingRow() { + public void getWifiSlice_oneConnectedAp_shouldReturnLoadingRow() { + setWorkerResults(createWifiSliceItem(AP1_NAME, WifiEntry.CONNECTED_STATE_CONNECTED)); + + final Slice wifiSlice = mWifiSlice.getSlice(); + final List sliceItems = wifiSlice.getItems(); + + SliceTester.assertAnySliceItemContainsTitle(sliceItems, AP1_NAME); + // Has scanning text + SliceTester.assertAnySliceItemContainsSubtitle(sliceItems, + mContext.getString(R.string.wifi_empty_list_wifi_on)); + } + + @Test + public void getWifiSlice_oneConnectedApAndOneDisconnectedAp_shouldReturnLoadingRow() { setWorkerResults( - createAccessPoint(AP1_NAME, false, false), - createAccessPoint(AP2_NAME, false, false)); + createWifiSliceItem(AP1_NAME, WifiEntry.CONNECTED_STATE_CONNECTED), + createWifiSliceItem(AP2_NAME, WifiEntry.CONNECTED_STATE_DISCONNECTED)); final Slice wifiSlice = mWifiSlice.getSlice(); final List sliceItems = wifiSlice.getItems(); @@ -177,8 +180,8 @@ public class WifiSliceTest { } @Test - public void getWifiSlice_oneActiveAp_shouldReturnLoadingRow() { - setWorkerResults(createAccessPoint(AP1_NAME, true, true)); + public void getWifiSlice_oneDisconnectedAp_shouldReturnLoadingRow() { + setWorkerResults(createWifiSliceItem(AP1_NAME, WifiEntry.CONNECTED_STATE_DISCONNECTED)); final Slice wifiSlice = mWifiSlice.getSlice(); final List sliceItems = wifiSlice.getItems(); @@ -190,40 +193,11 @@ public class WifiSliceTest { } @Test - public void getWifiSlice_oneActiveApAndOneUnreachableAp_shouldReturnLoadingRow() { + public void getWifiSlice_apReachExpandedCount_shouldNotReturnLoadingRow() { setWorkerResults( - createAccessPoint(AP1_NAME, true, true), - createAccessPoint(AP2_NAME, false, false)); - - final Slice wifiSlice = mWifiSlice.getSlice(); - final List sliceItems = wifiSlice.getItems(); - - SliceTester.assertAnySliceItemContainsTitle(sliceItems, AP1_NAME); - SliceTester.assertAnySliceItemContainsTitle(sliceItems, AP2_NAME); - // Has scanning text - SliceTester.assertAnySliceItemContainsSubtitle(sliceItems, - mContext.getString(R.string.wifi_empty_list_wifi_on)); - } - - @Test - public void getWifiSlice_oneReachableAp_shouldReturnLoadingRow() { - setWorkerResults(createAccessPoint(AP1_NAME, false, true)); - - final Slice wifiSlice = mWifiSlice.getSlice(); - final List sliceItems = wifiSlice.getItems(); - - SliceTester.assertAnySliceItemContainsTitle(sliceItems, AP1_NAME); - // Has scanning text - SliceTester.assertAnySliceItemContainsSubtitle(sliceItems, - mContext.getString(R.string.wifi_empty_list_wifi_on)); - } - - @Test - public void getWifiSlice_allReachableAps_shouldNotReturnLoadingRow() { - setWorkerResults( - createAccessPoint(AP1_NAME, false, true), - createAccessPoint(AP2_NAME, false, true), - createAccessPoint(AP3_NAME, false, true)); + createWifiSliceItem(AP1_NAME, WifiEntry.CONNECTED_STATE_DISCONNECTED), + createWifiSliceItem(AP2_NAME, WifiEntry.CONNECTED_STATE_DISCONNECTED), + createWifiSliceItem(AP3_NAME, WifiEntry.CONNECTED_STATE_DISCONNECTED)); final Slice wifiSlice = mWifiSlice.getSlice(); final List sliceItems = wifiSlice.getItems(); @@ -236,29 +210,6 @@ public class WifiSliceTest { mContext.getString(R.string.wifi_empty_list_wifi_on)); } - @Test - public void getWifiSlice_isCaptivePortal_shouldHaveCaptivePortalItems() { - setWorkerResults(createAccessPoint(AP1_NAME, true, true)); - doReturn(makeCaptivePortalNetworkCapabilities()).when(mConnectivityManager) - .getNetworkCapabilities(any()); - final IconCompat expectedIcon = IconCompat.createWithResource(mContext, - R.drawable.ic_settings_accent); - - final Slice wifiSlice = mWifiSlice.getSlice(); - final List sliceItems = wifiSlice.getItems(); - - SliceTester.assertAnySliceItemContainsTitle(sliceItems, AP1_NAME); - SliceTester.assertAnySliceItemContainsIcon(sliceItems, expectedIcon); - } - - static NetworkCapabilities makeCaptivePortalNetworkCapabilities() { - final NetworkCapabilities nc = new NetworkCapabilities(); - nc.clearAll(); - nc.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); - nc.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL); - return nc; - } - @Test public void handleUriChange_updatesWifi() { final Intent intent = mWifiSlice.getIntent();