Merge "[Wi-Fi] Apply WifiTrackerLib objects in Wi-Fi Slice"

This commit is contained in:
Arc Wang
2020-07-23 01:38:08 +00:00
committed by Android (Google) Code Review
15 changed files with 493 additions and 813 deletions

View File

@@ -2201,6 +2201,8 @@
<string name="wifi_turned_on_message">Wi\u2011Fi turned on</string> <string name="wifi_turned_on_message">Wi\u2011Fi turned on</string>
<!-- A notification for connected to a Wi-Fi network [CHAR LIMIT=NONE] --> <!-- A notification for connected to a Wi-Fi network [CHAR LIMIT=NONE] -->
<string name="wifi_connected_to_message">Connected to <xliff:g id="network_name" example="MyNetwork">%1$s</xliff:g></string> <string name="wifi_connected_to_message">Connected to <xliff:g id="network_name" example="MyNetwork">%1$s</xliff:g></string>
<!-- A notification for connecting to a Wi-Fi network [CHAR LIMIT=NONE] -->
<string name="wifi_connecting_to_message">Connecting to <xliff:g id="network_name" example="MyNetwork">%1$s</xliff:g></string>
<!-- Button label to connecting progress to a Wi-Fi network [CHAR LIMIT=20] --> <!-- Button label to connecting progress to a Wi-Fi network [CHAR LIMIT=20] -->
<string name="wifi_connecting">Connecting\u2026</string> <string name="wifi_connecting">Connecting\u2026</string>
<!-- Failured notification for connect --> <!-- Failured notification for connect -->

View File

@@ -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.BluetoothUpdateWorker;
import com.android.settings.homepage.contextualcards.slices.SwipeDismissalDelegate; import com.android.settings.homepage.contextualcards.slices.SwipeDismissalDelegate;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settings.wifi.slice.ContextualWifiScanWorker;
public class ContextualCardsFragment extends InstrumentedFragment implements public class ContextualCardsFragment extends InstrumentedFragment implements
FocusRecyclerView.FocusListener { FocusRecyclerView.FocusListener {
@@ -80,7 +79,6 @@ public class ContextualCardsFragment extends InstrumentedFragment implements
super.onStart(); super.onStart();
registerScreenOffReceiver(); registerScreenOffReceiver();
registerKeyEventReceiver(); registerKeyEventReceiver();
ContextualWifiScanWorker.newVisibleUiSession();
mContextualCardManager.loadContextualCards(LoaderManager.getInstance(this), mContextualCardManager.loadContextualCards(LoaderManager.getInstance(this),
sRestartLoaderNeeded); sRestartLoaderNeeded);
sRestartLoaderNeeded = false; sRestartLoaderNeeded = false;

View File

@@ -32,6 +32,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.core.InstrumentedFragment; import com.android.settings.core.InstrumentedFragment;
import com.android.settings.wifi.dpp.WifiDppQrCodeScannerFragment;
import com.android.settings.wifi.dpp.WifiDppUtils; import com.android.settings.wifi.dpp.WifiDppUtils;
/** /**
@@ -116,7 +117,7 @@ public class AddNetworkFragment extends InstrumentedFragment implements WifiConf
} }
final WifiConfiguration config = data.getParcelableExtra( final WifiConfiguration config = data.getParcelableExtra(
WifiDialogActivity.KEY_WIFI_CONFIGURATION); WifiDppQrCodeScannerFragment.KEY_WIFI_CONFIGURATION);
successfullyFinish(config); successfullyFinish(config);
} }
} }

View File

@@ -57,7 +57,6 @@ import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProviders;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.wifi.WifiDialogActivity;
import com.android.settings.wifi.qrcode.QrCamera; import com.android.settings.wifi.qrcode.QrCamera;
import com.android.settings.wifi.qrcode.QrDecorateView; import com.android.settings.wifi.qrcode.QrDecorateView;
import com.android.wifitrackerlib.WifiEntry; import com.android.wifitrackerlib.WifiEntry;
@@ -91,7 +90,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
// Key for Bundle usage // Key for Bundle usage
private static final String KEY_IS_CONFIGURATOR_MODE = "key_is_configurator_mode"; 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_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; private static final int ARG_RESTART_CAMERA = 1;
@@ -689,8 +688,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
@Override @Override
public void onSuccess() { public void onSuccess() {
final Intent resultIntent = new Intent(); final Intent resultIntent = new Intent();
resultIntent.putExtra(WifiDialogActivity.KEY_WIFI_CONFIGURATION, resultIntent.putExtra(KEY_WIFI_CONFIGURATION, mEnrolleeWifiConfiguration);
mEnrolleeWifiConfiguration);
final Activity hostActivity = getActivity(); final Activity hostActivity = getActivity();
hostActivity.setResult(Activity.RESULT_OK, resultIntent); hostActivity.setResult(Activity.RESULT_OK, resultIntent);

View File

@@ -19,61 +19,74 @@ package com.android.settings.wifi.slice;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.ConnectivityManager; import android.text.TextUtils;
import android.net.Network; import android.widget.Toast;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import androidx.annotation.VisibleForTesting; 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.WifiDialogActivity;
import com.android.settings.wifi.WifiUtils; import com.android.wifitrackerlib.WifiEntry;
import com.android.settingslib.wifi.AccessPoint; import com.android.wifitrackerlib.WifiEntry.ConnectCallback;
/** /**
* This receiver helps connect to Wi-Fi network * This receiver helps connect to Wi-Fi network
*/ */
public class ConnectToWifiHandler extends BroadcastReceiver { 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 @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (context == null || intent == null) { if (context == null || intent == null) {
return; return;
} }
final String key = intent.getStringExtra(KEY_CHOSEN_WIFIENTRY_KEY);
final Network network = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK); if (TextUtils.isEmpty(key)) {
final Bundle accessPointState = intent.getBundleExtra( return;
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));
} }
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 @VisibleForTesting
void connect(Context context, AccessPoint accessPoint) { WifiScanWorker getWifiScanWorker(Intent intent) {
ContextualWifiScanWorker.saveSession(); return SliceBackgroundWorker.getInstance(intent.getParcelableExtra(KEY_WIFI_SLICE_URI));
WifiScanWorker.saveClickedWifi(accessPoint); }
final WifiConnectListener connectListener = new WifiConnectListener(context); @VisibleForTesting
switch (WifiUtils.getConnectingType(accessPoint)) { static class WifiEntryConnectCallback implements WifiEntry.ConnectCallback {
case WifiUtils.CONNECT_TYPE_OSU_PROVISION: final Context mContext;
accessPoint.startOsuProvisioning(connectListener); final WifiEntry mWifiEntry;
break;
case WifiUtils.CONNECT_TYPE_OPEN_NETWORK: WifiEntryConnectCallback(Context context, WifiEntry connectWifiEntry) {
accessPoint.generateOpenNetworkConfig(); mContext = context;
mWifiEntry = connectWifiEntry;
}
case WifiUtils.CONNECT_TYPE_SAVED_NETWORK: @Override
final WifiManager wifiManager = context.getSystemService(WifiManager.class); public void onConnectResult(@ConnectStatus int status) {
wifiManager.connect(accessPoint.getConfig(), connectListener); if (status == ConnectCallback.CONNECT_STATUS_FAILURE_NO_CONFIG) {
break; 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();
}
} }
} }
} }

View File

@@ -18,7 +18,6 @@ package com.android.settings.wifi.slice;
import android.content.Context; import android.content.Context;
import android.net.Uri; import android.net.Uri;
import android.os.SystemClock;
import com.android.settings.slices.SliceBackgroundWorker; import com.android.settings.slices.SliceBackgroundWorker;
@@ -27,44 +26,12 @@ import com.android.settings.slices.SliceBackgroundWorker;
*/ */
public class ContextualWifiScanWorker extends WifiScanWorker { public class ContextualWifiScanWorker extends WifiScanWorker {
private static long sVisibleUiSessionToken;
private static long sActiveSession;
public ContextualWifiScanWorker(Context context, Uri uri) { public ContextualWifiScanWorker(Context context, Uri uri) {
super(context, 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 @Override
protected int getApRowCount() { protected int getApRowCount() {
return ContextualWifiSlice.getApRowCount(); return ContextualWifiSlice.getApRowCount();
} }
} }

View File

@@ -18,10 +18,8 @@ package com.android.settings.wifi.slice;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities; 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.Uri;
import android.net.wifi.WifiInfo; import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
@@ -37,7 +35,7 @@ import com.android.settings.Utils;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settings.slices.CustomSliceRegistry; import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.slices.CustomSliceable; 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. * {@link CustomSliceable} for Wi-Fi, used by contextual homepage.
@@ -52,8 +50,12 @@ public class ContextualWifiSlice extends WifiSlice {
@VisibleForTesting @VisibleForTesting
static boolean sApRowCollapsed; static boolean sApRowCollapsed;
private final ConnectivityManager mConnectivityManager;
public ContextualWifiSlice(Context context) { public ContextualWifiSlice(Context context) {
super(context); super(context);
mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
} }
@Override @Override
@@ -84,16 +86,17 @@ public class ContextualWifiSlice extends WifiSlice {
} }
@Override @Override
protected ListBuilder.RowBuilder getHeaderRow(boolean isWifiEnabled, AccessPoint accessPoint) { protected ListBuilder.RowBuilder getHeaderRow(boolean isWifiEnabled,
final ListBuilder.RowBuilder builder = super.getHeaderRow(isWifiEnabled, accessPoint); WifiSliceItem wifiSliceItem) {
builder.setTitleItem(getHeaderIcon(isWifiEnabled, accessPoint), ListBuilder.ICON_IMAGE); final ListBuilder.RowBuilder builder = super.getHeaderRow(isWifiEnabled, wifiSliceItem);
builder.setTitleItem(getHeaderIcon(isWifiEnabled, wifiSliceItem), ListBuilder.ICON_IMAGE);
if (sApRowCollapsed) { if (sApRowCollapsed) {
builder.setSubtitle(getSubtitle(accessPoint)); builder.setSubtitle(getHeaderSubtitle(wifiSliceItem));
} }
return builder; return builder;
} }
private IconCompat getHeaderIcon(boolean isWifiEnabled, AccessPoint accessPoint) { private IconCompat getHeaderIcon(boolean isWifiEnabled, WifiSliceItem wifiSliceItem) {
final Drawable drawable; final Drawable drawable;
final int tint; final int tint;
if (!isWifiEnabled) { if (!isWifiEnabled) {
@@ -103,7 +106,8 @@ public class ContextualWifiSlice extends WifiSlice {
} else { } else {
// get icon of medium signal strength // get icon of medium signal strength
drawable = mContext.getDrawable(com.android.settingslib.Utils.getWifiIconResource(2)); 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); tint = Utils.getColorAccentDefaultColor(mContext);
} else { } else {
tint = Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal); tint = Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal);
@@ -113,49 +117,16 @@ public class ContextualWifiSlice extends WifiSlice {
return Utils.createIconWithDrawable(drawable); return Utils.createIconWithDrawable(drawable);
} }
private boolean isNetworkConnected(AccessPoint accessPoint) { private CharSequence getHeaderSubtitle(WifiSliceItem wifiSliceItem) {
if (accessPoint == null) { if (wifiSliceItem == null
return false; || wifiSliceItem.getConnectedState() == WifiEntry.CONNECTED_STATE_DISCONNECTED) {
}
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) {
return mContext.getText(R.string.disconnected); return mContext.getText(R.string.disconnected);
} }
if (wifiSliceItem.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTING) {
final NetworkInfo networkInfo = accessPoint.getNetworkInfo(); return mContext.getString(R.string.wifi_connecting_to_message,
if (networkInfo == null) { wifiSliceItem.getTitle());
return mContext.getText(R.string.disconnected);
} }
return mContext.getString(R.string.wifi_connected_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());
} }
private boolean hasWorkingNetwork() { private boolean hasWorkingNetwork() {

View File

@@ -16,243 +16,187 @@
package com.android.settings.wifi.slice; 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 static com.android.settings.wifi.slice.WifiSlice.DEFAULT_EXPANDED_ROW_COUNT;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback; import android.net.NetworkScoreManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.Uri; import android.net.Uri;
import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager;
import android.os.Bundle; import android.os.HandlerThread;
import android.os.Handler; import android.os.Process;
import android.os.Looper; import android.os.SimpleClock;
import android.os.UserHandle; import android.os.SystemClock;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.VisibleForTesting; 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.settings.slices.SliceBackgroundWorker;
import com.android.settingslib.wifi.AccessPoint; import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.wifi.WifiTracker; 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.ArrayList;
import java.util.List; import java.util.List;
/** /**
* {@link SliceBackgroundWorker} for Wi-Fi, used by {@link WifiSlice}. * {@link SliceBackgroundWorker} for Wi-Fi, used by {@link WifiSlice}.
*/ */
public class WifiScanWorker extends SliceBackgroundWorker<AccessPoint> implements public class WifiScanWorker extends SliceBackgroundWorker<WifiSliceItem> implements
WifiTracker.WifiListener { WifiPickerTracker.WifiPickerTrackerCallback, LifecycleOwner, WifiEntryCallback {
private static final String TAG = "WifiScanWorker"; 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 @VisibleForTesting
WifiNetworkCallback mNetworkCallback; final LifecycleRegistry mLifecycleRegistry;
@VisibleForTesting
private final Context mContext; WifiPickerTracker mWifiPickerTracker;
private final ConnectivityManager mConnectivityManager; // Worker thread used for WifiPickerTracker work
private final WifiTracker mWifiTracker; private final HandlerThread mWorkerThread;
private static String sClickedWifiSsid;
public WifiScanWorker(Context context, Uri uri) { public WifiScanWorker(Context context, Uri uri) {
super(context, uri); super(context, uri);
mContext = context;
mConnectivityManager = context.getSystemService(ConnectivityManager.class); mLifecycleRegistry = new LifecycleRegistry(this);
mWifiTracker = new WifiTracker(mContext, this /* wifiListener */,
true /* includeSaved */, true /* includeScans */); 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 @Override
protected void onSlicePinned() { protected void onSlicePinned() {
mWifiTracker.onStart(); mLifecycleRegistry.markState(Lifecycle.State.STARTED);
onAccessPointsChanged(); mLifecycleRegistry.markState(Lifecycle.State.RESUMED);
updateResults();
} }
@Override @Override
protected void onSliceUnpinned() { protected void onSliceUnpinned() {
mWifiTracker.onStop(); mLifecycleRegistry.markState(Lifecycle.State.STARTED);
unregisterNetworkCallback(); mLifecycleRegistry.markState(Lifecycle.State.CREATED);
clearClickedWifiOnSliceUnpinned();
} }
@Override @Override
public void close() { public void close() {
mWifiTracker.onDestroy(); mLifecycleRegistry.markState(Lifecycle.State.DESTROYED);
mWorkerThread.quit();
} }
@Override @Override
public void onWifiStateChanged(int state) { public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
/** Called when the state of Wifi has changed. */
@Override
public void onWifiStateChanged() {
notifySliceChange(); notifySliceChange();
} }
/**
* Update the results when data changes
*/
@Override @Override
public void onConnectedChanged() { public void onWifiEntriesChanged() {
updateResults();
} }
/**
* Indicates the state of the WifiEntry has changed and clients may retrieve updates through
* the WifiEntry getter methods.
*/
@Override @Override
public void onAccessPointsChanged() { public void onUpdated() {
// in case state has changed updateResults();
if (!mWifiTracker.getManager().isWifiEnabled()) {
updateResults(null);
return;
}
// AccessPoints are sorted by the WifiTracker
final List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
final List<AccessPoint> 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() { protected int getApRowCount() {
return DEFAULT_EXPANDED_ROW_COUNT; return DEFAULT_EXPANDED_ROW_COUNT;
} }
private AccessPoint clone(AccessPoint accessPoint) { @Override
final Bundle savedState = new Bundle(); public void onNumSavedSubscriptionsChanged() {
accessPoint.saveWifiState(savedState); // Do nothing.
return new AccessPoint(mContext, savedState);
} }
@Override @Override
protected boolean areListsTheSame(List<AccessPoint> a, List<AccessPoint> b) { public void onNumSavedNetworksChanged() {
if (!a.equals(b)) { // Do nothing.
return false; }
}
// compare access point states one by one /**
final int listSize = a.size(); * To get the WifiEntry of key.
for (int i = 0; i < listSize; i++) { */
if (a.get(i).getDetailedState() != b.get(i).getDetailedState()) { public WifiEntry getWifiEntry(String key) {
return false; // 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) { @VisibleForTesting
sClickedWifiSsid = accessPoint.getSsidStr(); void updateResults() {
} if (mWifiPickerTracker.getWifiState() != WifiManager.WIFI_STATE_ENABLED
|| mLifecycleRegistry.getCurrentState() != Lifecycle.State.RESUMED) {
static void clearClickedWifi() { super.updateResults(null);
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) {
return; return;
} }
if (mNetworkCallback != null && mNetworkCallback.isSameNetwork(wifiNetwork)) { final List<WifiSliceItem> resultList = new ArrayList<>();
return; final WifiEntry connectedWifiEntry = mWifiPickerTracker.getConnectedWifiEntry();
if (connectedWifiEntry != null) {
connectedWifiEntry.setListener(this);
resultList.add(new WifiSliceItem(getContext(), connectedWifiEntry));
} }
for (WifiEntry wifiEntry : mWifiPickerTracker.getWifiEntries()) {
unregisterNetworkCallback(); if (resultList.size() >= getApRowCount()) {
break;
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);
} }
mNetworkCallback = null; if (wifiEntry.getLevel() != WifiEntry.WIFI_LEVEL_UNREACHABLE) {
} wifiEntry.setListener(this);
} resultList.add(new WifiSliceItem(getContext(), wifiEntry));
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);
} }
} }
super.updateResults(resultList);
/**
* 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);
}
} }
} }

View File

@@ -29,9 +29,6 @@ import android.content.Intent;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.Uri; import android.net.Uri;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.Bundle; import android.os.Bundle;
@@ -52,9 +49,8 @@ import com.android.settings.slices.SliceBackgroundWorker;
import com.android.settings.slices.SliceBuilderUtils; import com.android.settings.slices.SliceBuilderUtils;
import com.android.settings.wifi.WifiDialogActivity; import com.android.settings.wifi.WifiDialogActivity;
import com.android.settings.wifi.WifiSettings; import com.android.settings.wifi.WifiSettings;
import com.android.settings.wifi.WifiUtils; import com.android.settings.wifi.details2.WifiNetworkDetailsFragment2;
import com.android.settings.wifi.details.WifiNetworkDetailsFragment; import com.android.wifitrackerlib.WifiEntry;
import com.android.settingslib.wifi.AccessPoint;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -71,12 +67,10 @@ public class WifiSlice implements CustomSliceable {
protected final Context mContext; protected final Context mContext;
protected final WifiManager mWifiManager; protected final WifiManager mWifiManager;
protected final ConnectivityManager mConnectivityManager;
public WifiSlice(Context context) { public WifiSlice(Context context) {
mContext = context; mContext = context;
mWifiManager = mContext.getSystemService(WifiManager.class); mWifiManager = mContext.getSystemService(WifiManager.class);
mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
} }
@Override @Override
@@ -87,17 +81,16 @@ public class WifiSlice implements CustomSliceable {
@Override @Override
public Slice getSlice() { public Slice getSlice() {
final boolean isWifiEnabled = isWifiEnabled(); final boolean isWifiEnabled = isWifiEnabled();
ListBuilder listBuilder = getListBuilder(isWifiEnabled, null /* accessPoint */); ListBuilder listBuilder = getListBuilder(isWifiEnabled, null /* wifiSliceItem */);
if (!isWifiEnabled) { if (!isWifiEnabled) {
WifiScanWorker.clearClickedWifi();
return listBuilder.build(); return listBuilder.build();
} }
final WifiScanWorker worker = SliceBackgroundWorker.getInstance(getUri()); final WifiScanWorker worker = SliceBackgroundWorker.getInstance(getUri());
final List<AccessPoint> apList = worker != null ? worker.getResults() : null; final List<WifiSliceItem> apList = worker != null ? worker.getResults() : null;
final int apCount = apList == null ? 0 : apList.size(); final int apCount = apList == null ? 0 : apList.size();
final boolean isFirstApActive = apCount > 0 && apList.get(0).isActive(); final boolean isFirstApActive = apCount > 0
handleNetworkCallback(worker, isFirstApActive); && apList.get(0).getConnectedState() != WifiEntry.CONNECTED_STATE_DISCONNECTED;
if (isFirstApActive) { if (isFirstApActive) {
// refresh header subtext // refresh header subtext
@@ -112,7 +105,7 @@ public class WifiSlice implements CustomSliceable {
final CharSequence placeholder = mContext.getText(R.string.summary_placeholder); final CharSequence placeholder = mContext.getText(R.string.summary_placeholder);
for (int i = 0; i < DEFAULT_EXPANDED_ROW_COUNT; i++) { for (int i = 0; i < DEFAULT_EXPANDED_ROW_COUNT; i++) {
if (i < apCount) { if (i < apCount) {
listBuilder.addRow(getAccessPointRow(apList.get(i))); listBuilder.addRow(getWifiSliceItemRow(apList.get(i)));
} else if (i == apCount) { } else if (i == apCount) {
listBuilder.addRow(getLoadingRow(placeholder)); listBuilder.addRow(getLoadingRow(placeholder));
} else { } else {
@@ -124,22 +117,12 @@ public class WifiSlice implements CustomSliceable {
return listBuilder.build(); 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() { protected boolean isApRowCollapsed() {
return false; return false;
} }
protected ListBuilder.RowBuilder getHeaderRow(boolean isWifiEnabled, AccessPoint accessPoint) { protected ListBuilder.RowBuilder getHeaderRow(boolean isWifiEnabled,
WifiSliceItem wifiSliceItem) {
final IconCompat icon = IconCompat.createWithResource(mContext, final IconCompat icon = IconCompat.createWithResource(mContext,
R.drawable.ic_settings_wireless); R.drawable.ic_settings_wireless);
final String title = mContext.getString(R.string.wifi_settings); final String title = mContext.getString(R.string.wifi_settings);
@@ -152,115 +135,90 @@ public class WifiSlice implements CustomSliceable {
.setPrimaryAction(primarySliceAction); .setPrimaryAction(primarySliceAction);
} }
private ListBuilder getListBuilder(boolean isWifiEnabled, AccessPoint accessPoint) { private ListBuilder getListBuilder(boolean isWifiEnabled, WifiSliceItem wifiSliceItem) {
final PendingIntent toggleAction = getBroadcastIntent(mContext); final PendingIntent toggleAction = getBroadcastIntent(mContext);
final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction, final SliceAction toggleSliceAction = SliceAction.createToggle(toggleAction,
null /* actionTitle */, isWifiEnabled); null /* actionTitle */, isWifiEnabled);
final ListBuilder builder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY) final ListBuilder builder = new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
.setAccentColor(COLOR_NOT_TINTED) .setAccentColor(COLOR_NOT_TINTED)
.setKeywords(getKeywords()) .setKeywords(getKeywords())
.addRow(getHeaderRow(isWifiEnabled, accessPoint)) .addRow(getHeaderRow(isWifiEnabled, wifiSliceItem))
.addAction(toggleSliceAction); .addAction(toggleSliceAction);
return builder; return builder;
} }
private ListBuilder.RowBuilder getAccessPointRow(AccessPoint accessPoint) { private ListBuilder.RowBuilder getWifiSliceItemRow(WifiSliceItem wifiSliceItem) {
final boolean isCaptivePortal = accessPoint.isActive() && isCaptivePortal(); final CharSequence title = wifiSliceItem.getTitle();
final CharSequence title = accessPoint.getTitle(); final IconCompat levelIcon = getWifiSliceItemLevelIcon(wifiSliceItem);
final CharSequence summary = getAccessPointSummary(accessPoint, isCaptivePortal);
final IconCompat levelIcon = getAccessPointLevelIcon(accessPoint);
final ListBuilder.RowBuilder rowBuilder = new ListBuilder.RowBuilder() final ListBuilder.RowBuilder rowBuilder = new ListBuilder.RowBuilder()
.setTitleItem(levelIcon, ListBuilder.ICON_IMAGE) .setTitleItem(levelIcon, ListBuilder.ICON_IMAGE)
.setTitle(title) .setTitle(title)
.setSubtitle(summary) .setSubtitle(wifiSliceItem.getSummary())
.setPrimaryAction(getAccessPointAction(accessPoint, isCaptivePortal, levelIcon, .setContentDescription(wifiSliceItem.getContentDescription())
title)); .setPrimaryAction(getWifiEntryAction(wifiSliceItem, levelIcon, title));
if (isCaptivePortal) { final IconCompat endIcon = getEndIcon(wifiSliceItem);
rowBuilder.addEndItem(getCaptivePortalEndAction(accessPoint, title)); if (endIcon != null) {
} else { rowBuilder.addEndItem(endIcon, ListBuilder.ICON_IMAGE);
final IconCompat endIcon = getEndIcon(accessPoint);
if (endIcon != null) {
rowBuilder.addEndItem(endIcon, ListBuilder.ICON_IMAGE);
}
} }
return rowBuilder; return rowBuilder;
} }
private CharSequence getAccessPointSummary(AccessPoint accessPoint, boolean isCaptivePortal) { private IconCompat getWifiSliceItemLevelIcon(WifiSliceItem wifiSliceItem) {
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) {
final @ColorInt int tint; final @ColorInt int tint;
if (accessPoint.isActive()) { if (wifiSliceItem.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED) {
final NetworkInfo.State state = accessPoint.getNetworkInfo().getState(); tint = Utils.getColorAccentDefaultColor(mContext);
if (state == NetworkInfo.State.CONNECTED) { } else if (wifiSliceItem.getConnectedState() == WifiEntry.CONNECTED_STATE_DISCONNECTED) {
tint = Utils.getColorAccentDefaultColor(mContext);
} else { // connecting
tint = Utils.getDisabled(mContext, Utils.getColorAttrDefaultColor(mContext,
android.R.attr.colorControlNormal));
}
} else {
tint = Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal); 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( final Drawable drawable = mContext.getDrawable(
com.android.settingslib.Utils.getWifiIconResource(accessPoint.getLevel())); com.android.settingslib.Utils.getWifiIconResource(wifiSliceItem.getLevel()));
drawable.setTint(tint); drawable.setTint(tint);
return Utils.createIconWithDrawable(drawable); return Utils.createIconWithDrawable(drawable);
} }
private IconCompat getEndIcon(AccessPoint accessPoint) { private IconCompat getEndIcon(WifiSliceItem wifiSliceItem) {
if (accessPoint.isActive()) { if (wifiSliceItem.getConnectedState() != WifiEntry.CONNECTED_STATE_DISCONNECTED) {
return null; 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); 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; return null;
} }
private SliceAction getCaptivePortalEndAction(AccessPoint accessPoint, CharSequence title) { private SliceAction getWifiEntryAction(WifiSliceItem wifiSliceItem, IconCompat icon,
return getAccessPointAction(accessPoint, false /* isCaptivePortal */, CharSequence title) {
IconCompat.createWithResource(mContext, R.drawable.ic_settings_accent), title); final int requestCode = wifiSliceItem.getKey().hashCode();
}
private SliceAction getAccessPointAction(AccessPoint accessPoint, boolean isCaptivePortal, if (wifiSliceItem.getConnectedState() != WifiEntry.CONNECTED_STATE_DISCONNECTED) {
IconCompat icon, CharSequence title) { final Bundle bundle = new Bundle();
final int requestCode = accessPoint.hashCode(); bundle.putString(WifiNetworkDetailsFragment2.KEY_CHOSEN_WIFIENTRY_KEY,
if (isCaptivePortal) { wifiSliceItem.getKey());
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()) {
final Intent intent = new SubSettingLauncher(mContext) final Intent intent = new SubSettingLauncher(mContext)
.setTitleRes(R.string.pref_title_network_details) .setTitleRes(R.string.pref_title_network_details)
.setDestination(WifiNetworkDetailsFragment.class.getName()) .setDestination(WifiNetworkDetailsFragment2.class.getName())
.setArguments(extras) .setArguments(bundle)
.setSourceMetricsCategory(SettingsEnums.WIFI) .setSourceMetricsCategory(SettingsEnums.WIFI)
.toIntent(); .toIntent();
return getActivityAction(requestCode, intent, icon, title); 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); if (wifiSliceItem.shouldEditBeforeConnect()) {
return getBroadcastAction(requestCode, intent, icon, title);
} else {
final Intent intent = new Intent(mContext, WifiDialogActivity.class) 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); 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, private SliceAction getActivityAction(int requestCode, Intent intent, IconCompat icon,
@@ -291,12 +249,6 @@ public class WifiSlice implements CustomSliceable {
.setSubtitle(title); .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 * Update the current wifi status to the boolean value keyed by
* {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}. * {@link android.app.slice.Slice#EXTRA_TOGGLE_STATE} on {@param intent}.

View File

@@ -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));
}
}

View File

@@ -18,6 +18,7 @@ package com.android.settings.testutils.shadow;
import static org.robolectric.RuntimeEnvironment.application; import static org.robolectric.RuntimeEnvironment.application;
import android.net.wifi.ScanResult;
import android.net.wifi.SoftApConfiguration; import android.net.wifi.SoftApConfiguration;
import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
@@ -81,6 +82,11 @@ public class ShadowWifiManager extends org.robolectric.shadows.ShadowWifiManager
return false; return false;
} }
@Implementation
protected List<ScanResult> getScanResults() {
return new ArrayList<ScanResult>();
}
public static ShadowWifiManager get() { public static ShadowWifiManager get() {
return Shadow.extract(application.getSystemService(WifiManager.class)); return Shadow.extract(application.getSystemService(WifiManager.class));
} }

View File

@@ -26,95 +26,69 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.net.wifi.WifiConfiguration; import android.content.Intent;
import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
import android.net.wifi.WifiManager;
import com.android.settings.testutils.shadow.ShadowWifiManager; import com.android.settings.wifi.WifiDialogActivity;
import com.android.settingslib.wifi.AccessPoint; import com.android.wifitrackerlib.WifiEntry;
import com.android.wifitrackerlib.WifiEntry.ConnectCallback;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowWifiManager.class)
public class ConnectToWifiHandlerTest { public class ConnectToWifiHandlerTest {
private static final String AP_SSID = "\"ap\""; private static final String AP_SSID = "\"ap\"";
private Context mContext; private Context mContext;
private ConnectToWifiHandler mHandler; private ConnectToWifiHandler mHandler;
private WifiConfiguration mWifiConfig;
@Mock @Mock
private AccessPoint mAccessPoint; private WifiScanWorker mWifiScanWorker;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application; mContext = spy(RuntimeEnvironment.application);
mHandler = new ConnectToWifiHandler(); mHandler = spy(new ConnectToWifiHandler());
mWifiConfig = spy(new WifiConfiguration()); doReturn(mWifiScanWorker).when(mHandler).getWifiScanWorker(any());
mWifiConfig.SSID = AP_SSID;
doReturn(mWifiConfig).when(mAccessPoint).getConfig();
} }
@Test @Test
public void connect_shouldConnectToUnsavedOpenNetwork() { public void onReceive_nonNullKeyAndUri_shouldConnectWifintry() {
when(mAccessPoint.isSaved()).thenReturn(false); final Intent intent = new Intent();
when(mAccessPoint.getSecurity()).thenReturn(AccessPoint.SECURITY_NONE); 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 @Test
public void connect_shouldStartOsuProvisioning() { public void onConnectResult_failNoConfig_shouldStartActivity() {
when(mAccessPoint.isSaved()).thenReturn(false); final String key = "key";
when(mAccessPoint.isOsuProvider()).thenReturn(true); 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)); final ArgumentCaptor<Intent> argument = ArgumentCaptor.forClass(Intent.class);
} verify(mContext).startActivity(argument.capture());
assertThat(argument.getValue().getStringExtra(WifiDialogActivity.KEY_CHOSEN_WIFIENTRY_KEY))
.isEqualTo(key);
@Test assertThat(argument.getValue().getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK)
public void connect_shouldConnectWithPasspointProvider() { .isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK);
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();
} }
} }

View File

@@ -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));
}
}

View File

@@ -17,216 +17,89 @@
package com.android.settings.wifi.slice; package com.android.settings.wifi.slice;
import static com.android.settings.slices.CustomSliceRegistry.WIFI_SLICE_URI; 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 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.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 static org.mockito.Mockito.when;
import android.content.ContentResolver; import androidx.lifecycle.Lifecycle;
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 com.android.settings.slices.ShadowSliceBackgroundWorker; import com.android.wifitrackerlib.WifiEntry;
import com.android.settings.testutils.shadow.ShadowWifiManager; import com.android.wifitrackerlib.WifiPickerTracker;
import com.android.settingslib.wifi.AccessPoint;
import com.android.settingslib.wifi.WifiTracker;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; 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.Arrays;
import java.util.List;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowSliceBackgroundWorker.class, ShadowWifiManager.class,
WifiScanWorkerTest.ShadowWifiTracker.class})
public class WifiScanWorkerTest { public class WifiScanWorkerTest {
private Context mContext;
private ContentResolver mResolver;
private WifiManager mWifiManager;
private ConnectivityManager mConnectivityManager;
private WifiScanWorker mWifiScanWorker; private WifiScanWorker mWifiScanWorker;
private ConnectToWifiHandler mConnectToWifiHandler; @Mock
WifiPickerTracker mWifiPickerTracker;
@Before @Before
public void setUp() { public void setUp() {
mContext = spy(RuntimeEnvironment.application); MockitoAnnotations.initMocks(this);
mResolver = mock(ContentResolver.class);
doReturn(mResolver).when(mContext).getContentResolver();
mWifiManager = mContext.getSystemService(WifiManager.class);
mWifiManager.setWifiEnabled(true);
mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mWifiScanWorker = new WifiScanWorker(RuntimeEnvironment.application, WIFI_SLICE_URI);
mWifiScanWorker = new WifiScanWorker(mContext, WIFI_SLICE_URI); mWifiScanWorker.mWifiPickerTracker = mWifiPickerTracker;
mConnectToWifiHandler = new ConnectToWifiHandler();
}
@After
public void tearDown() {
mWifiScanWorker.clearClickedWifi();
} }
@Test @Test
public void onWifiStateChanged_shouldNotifyChange() { public void onConstructor_shouldBeInCreatedState() {
mWifiScanWorker.onWifiStateChanged(WifiManager.WIFI_STATE_DISABLED); assertThat(mWifiScanWorker.getLifecycle().getCurrentState())
.isEqualTo(Lifecycle.State.CREATED);
verify(mResolver).notifyChange(WIFI_SLICE_URI, null);
} }
@Test @Test
public void AccessPointList_sameState_shouldBeTheSame() { public void onSlicePinned_shouldBeInResumedState() {
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<AccessPoint> 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;
mWifiScanWorker.onSlicePinned(); mWifiScanWorker.onSlicePinned();
mConnectToWifiHandler.onReceive(mContext, intent);
assertThat(mWifiScanWorker.getLifecycle().getCurrentState())
.isEqualTo(Lifecycle.State.RESUMED);
}
@Test
public void onSliceUnpinned_shouldBeInCreatedState() {
mWifiScanWorker.onSliceUnpinned(); 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) { @Test
final Bundle savedState = new Bundle(); public void close_shouldBeInDestroyedState() {
savedState.putString("key_ssid", ssid); mWifiScanWorker.close();
return new Intent().putExtra(KEY_ACCESS_POINT_STATE, savedState);
assertThat(mWifiScanWorker.getLifecycle().getCurrentState())
.isEqualTo(Lifecycle.State.DESTROYED);
} }
static void setConnectionInfoSSID(String ssid) { @Test
final WifiInfo wifiInfo = mock(WifiInfo.class); public void getWifiEntry_connectedWifiKey_shouldGetConnectedWifi() {
when(wifiInfo.getSSID()).thenReturn(ssid); final String key = "key";
ShadowWifiManager.get().setConnectionInfo(wifiInfo); 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) { @Test
final NetworkInfo info = ShadowNetworkInfo.newInstance(detailedState, 1 /* type */, public void getWifiEntry_reachableWifiKey_shouldGetReachableWifi() {
0 /*subType */, true /* isAvailable */, true /* isConnected */); final String key = "key";
final Bundle savedState = new Bundle(); final WifiEntry reachableWifiEntry = mock(WifiEntry.class);
savedState.putString("key_ssid", ssid); when(reachableWifiEntry.getKey()).thenReturn(key);
savedState.putParcelable("key_networkinfo", info); when(mWifiPickerTracker.getWifiEntries()).thenReturn(Arrays.asList(reachableWifiEntry));
return new AccessPoint(mContext, savedState);
}
private AccessPoint createAccessPoint(DetailedState detailedState) { assertThat(mWifiScanWorker.getWifiEntry(key)).isEqualTo(reachableWifiEntry);
return createAccessPoint("ap", detailedState);
}
@Implements(WifiTracker.class)
public static class ShadowWifiTracker {
@Implementation
public void onStart() {
// do nothing
}
} }
} }

View File

@@ -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 com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.Uri; import android.net.Uri;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
@@ -49,7 +46,8 @@ import androidx.slice.widget.SliceLiveData;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.slices.SliceBackgroundWorker; import com.android.settings.slices.SliceBackgroundWorker;
import com.android.settings.testutils.SliceTester; 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.Before;
import org.junit.Test; import org.junit.Test;
@@ -74,7 +72,6 @@ public class WifiSliceTest {
private Context mContext; private Context mContext;
private ContentResolver mResolver; private ContentResolver mResolver;
private WifiManager mWifiManager; private WifiManager mWifiManager;
private ConnectivityManager mConnectivityManager;
private WifiSlice mWifiSlice; private WifiSlice mWifiSlice;
@Before @Before
@@ -88,9 +85,6 @@ public class WifiSliceTest {
SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
mWifiManager.setWifiEnabled(true); mWifiManager.setWifiEnabled(true);
mConnectivityManager = spy(mContext.getSystemService(ConnectivityManager.class));
doReturn(mConnectivityManager).when(mContext).getSystemService(ConnectivityManager.class);
mWifiSlice = new WifiSlice(mContext); mWifiSlice = new WifiSlice(mContext);
} }
@@ -138,33 +132,42 @@ public class WifiSliceTest {
mContext.getString(R.string.wifi_empty_list_wifi_on)); mContext.getString(R.string.wifi_empty_list_wifi_on));
} }
private AccessPoint createAccessPoint(String name, boolean active, boolean reachable) { private WifiSliceItem createWifiSliceItem(String title, @ConnectedState int connectedState) {
final AccessPoint accessPoint = mock(AccessPoint.class); final WifiEntry wifiEntry = mock(WifiEntry.class);
doReturn(name).when(accessPoint).getTitle(); when(wifiEntry.getTitle()).thenReturn(title);
doReturn(active).when(accessPoint).isActive(); when(wifiEntry.getKey()).thenReturn("key");
doReturn(reachable).when(accessPoint).isReachable(); when(wifiEntry.getConnectedState()).thenReturn(connectedState);
if (active) { when(wifiEntry.getLevel()).thenReturn(WifiEntry.WIFI_LEVEL_MAX);
final NetworkInfo networkInfo = mock(NetworkInfo.class); return new WifiSliceItem(mContext, wifiEntry);
doReturn(networkInfo).when(accessPoint).getNetworkInfo();
doReturn(NetworkInfo.State.CONNECTED).when(networkInfo).getState();
}
return accessPoint;
} }
private void setWorkerResults(AccessPoint... accessPoints) { private void setWorkerResults(WifiSliceItem... wifiSliceItems) {
final ArrayList<AccessPoint> results = new ArrayList<>(); final ArrayList<WifiSliceItem> results = new ArrayList<>();
for (AccessPoint ap : accessPoints) { for (WifiSliceItem wifiSliceItem : wifiSliceItems) {
results.add(ap); results.add(wifiSliceItem);
} }
final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance(mWifiSlice.getUri()); final SliceBackgroundWorker worker = SliceBackgroundWorker.getInstance(mWifiSlice.getUri());
doReturn(results).when(worker).getResults(); doReturn(results).when(worker).getResults();
} }
@Test @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<SliceItem> 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( setWorkerResults(
createAccessPoint(AP1_NAME, false, false), createWifiSliceItem(AP1_NAME, WifiEntry.CONNECTED_STATE_CONNECTED),
createAccessPoint(AP2_NAME, false, false)); createWifiSliceItem(AP2_NAME, WifiEntry.CONNECTED_STATE_DISCONNECTED));
final Slice wifiSlice = mWifiSlice.getSlice(); final Slice wifiSlice = mWifiSlice.getSlice();
final List<SliceItem> sliceItems = wifiSlice.getItems(); final List<SliceItem> sliceItems = wifiSlice.getItems();
@@ -177,8 +180,8 @@ public class WifiSliceTest {
} }
@Test @Test
public void getWifiSlice_oneActiveAp_shouldReturnLoadingRow() { public void getWifiSlice_oneDisconnectedAp_shouldReturnLoadingRow() {
setWorkerResults(createAccessPoint(AP1_NAME, true, true)); setWorkerResults(createWifiSliceItem(AP1_NAME, WifiEntry.CONNECTED_STATE_DISCONNECTED));
final Slice wifiSlice = mWifiSlice.getSlice(); final Slice wifiSlice = mWifiSlice.getSlice();
final List<SliceItem> sliceItems = wifiSlice.getItems(); final List<SliceItem> sliceItems = wifiSlice.getItems();
@@ -190,40 +193,11 @@ public class WifiSliceTest {
} }
@Test @Test
public void getWifiSlice_oneActiveApAndOneUnreachableAp_shouldReturnLoadingRow() { public void getWifiSlice_apReachExpandedCount_shouldNotReturnLoadingRow() {
setWorkerResults( setWorkerResults(
createAccessPoint(AP1_NAME, true, true), createWifiSliceItem(AP1_NAME, WifiEntry.CONNECTED_STATE_DISCONNECTED),
createAccessPoint(AP2_NAME, false, false)); createWifiSliceItem(AP2_NAME, WifiEntry.CONNECTED_STATE_DISCONNECTED),
createWifiSliceItem(AP3_NAME, WifiEntry.CONNECTED_STATE_DISCONNECTED));
final Slice wifiSlice = mWifiSlice.getSlice();
final List<SliceItem> 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<SliceItem> 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));
final Slice wifiSlice = mWifiSlice.getSlice(); final Slice wifiSlice = mWifiSlice.getSlice();
final List<SliceItem> sliceItems = wifiSlice.getItems(); final List<SliceItem> sliceItems = wifiSlice.getItems();
@@ -236,29 +210,6 @@ public class WifiSliceTest {
mContext.getString(R.string.wifi_empty_list_wifi_on)); 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<SliceItem> 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 @Test
public void handleUriChange_updatesWifi() { public void handleUriChange_updatesWifi() {
final Intent intent = mWifiSlice.getIntent(); final Intent intent = mWifiSlice.getIntent();