[Wi-Fi] Apply WifiDialog2 in WifiSetings2
This change also implements context menu in WifiSettings2. Bug: 70983952 Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=WifiSettings2Test Change-Id: I13b5a3724207f76e2b24fd0c1c49a236ee0c44f0
This commit is contained in:
@@ -19,9 +19,11 @@ package com.android.settings.wifi;
|
||||
import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.net.ConnectivityManager;
|
||||
@@ -38,10 +40,12 @@ import android.os.Process;
|
||||
import android.os.SimpleClock;
|
||||
import android.os.SystemClock;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.FeatureFlagUtils;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
@@ -64,27 +68,45 @@ import com.android.settings.location.ScanningSettings;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.widget.SwitchBarController;
|
||||
import com.android.settings.wifi.details2.WifiNetworkDetailsFragment2;
|
||||
import com.android.settings.wifi.dpp.WifiDppUtils;
|
||||
import com.android.settingslib.RestrictedLockUtils;
|
||||
import com.android.settingslib.RestrictedLockUtilsInternal;
|
||||
import com.android.settingslib.search.Indexable;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
import com.android.settingslib.search.SearchIndexableRaw;
|
||||
import com.android.settingslib.wifi.LongPressWifiEntryPreference;
|
||||
import com.android.wifitrackerlib.WifiEntry;
|
||||
import com.android.wifitrackerlib.WifiEntry.WifiEntryCallback;
|
||||
import com.android.wifitrackerlib.WifiEntry.WifiEntryCallback.ConnectStatus;
|
||||
import com.android.wifitrackerlib.WifiEntry.WifiEntryCallback.DisconnectStatus;
|
||||
import com.android.wifitrackerlib.WifiEntry.WifiEntryCallback.ForgetStatus;
|
||||
import com.android.wifitrackerlib.WifiEntry.WifiEntryCallback.SignInStatus;
|
||||
import com.android.wifitrackerlib.WifiPickerTracker;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* UI for Wi-Fi settings screen
|
||||
*/
|
||||
@SearchIndexable
|
||||
public class WifiSettings2 extends RestrictedSettingsFragment
|
||||
implements Indexable, WifiPickerTracker.WifiPickerTrackerCallback {
|
||||
implements Indexable, WifiPickerTracker.WifiPickerTrackerCallback,
|
||||
WifiDialog2.WifiDialog2Listener, DialogInterface.OnDismissListener {
|
||||
|
||||
private static final String TAG = "WifiSettings2";
|
||||
|
||||
// IDs of context menu
|
||||
static final int MENU_ID_CONNECT = Menu.FIRST + 1;
|
||||
@VisibleForTesting
|
||||
static final int MENU_ID_DISCONNECT = Menu.FIRST + 2;
|
||||
@VisibleForTesting
|
||||
static final int MENU_ID_FORGET = Menu.FIRST + 3;
|
||||
static final int MENU_ID_MODIFY = Menu.FIRST + 4;
|
||||
|
||||
// Max age of tracked WifiEntries
|
||||
private static final long MAX_SCAN_AGE_MILLIS = 15_000;
|
||||
// Interval between initiating WifiPickerTracker scans
|
||||
@@ -92,6 +114,7 @@ public class WifiSettings2 extends RestrictedSettingsFragment
|
||||
|
||||
@VisibleForTesting
|
||||
static final int ADD_NETWORK_REQUEST = 2;
|
||||
static final int CONFIG_NETWORK_REQUEST = 3;
|
||||
|
||||
private static final String PREF_KEY_EMPTY_WIFI_LIST = "wifi_empty_list";
|
||||
// TODO(b/70983952): Rename these to use WifiEntry instead of AccessPoint.
|
||||
@@ -105,6 +128,20 @@ public class WifiSettings2 extends RestrictedSettingsFragment
|
||||
|
||||
private static final int REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER = 0;
|
||||
|
||||
public static final int WIFI_DIALOG_ID = 1;
|
||||
|
||||
// Instance state keys
|
||||
private static final String SAVE_DIALOG_MODE = "dialog_mode";
|
||||
private static final String SAVE_DIALOG_WIFIENTRY_KEY = "wifi_ap_key";
|
||||
|
||||
// Cache at onCreateContextMenu and use at onContextItemSelected. Don't use it in other methods.
|
||||
private WifiEntry mSelectedWifiEntry;
|
||||
|
||||
// Save the dialog details
|
||||
private int mDialogMode;
|
||||
private String mDialogWifiEntryKey;
|
||||
private WifiEntry mDialogWifiEntry;
|
||||
|
||||
private static boolean isVerboseLoggingEnabled() {
|
||||
return WifiPickerTracker.isVerboseLoggingEnabled();
|
||||
}
|
||||
@@ -136,7 +173,7 @@ public class WifiSettings2 extends RestrictedSettingsFragment
|
||||
@VisibleForTesting
|
||||
WifiPickerTracker mWifiPickerTracker;
|
||||
|
||||
private WifiDialog mDialog;
|
||||
private WifiDialog2 mDialog;
|
||||
|
||||
private View mProgressHeader;
|
||||
|
||||
@@ -275,6 +312,23 @@ public class WifiSettings2 extends RestrictedSettingsFragment
|
||||
};
|
||||
registerForContextMenu(getListView());
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
mDialogMode = savedInstanceState.getInt(SAVE_DIALOG_MODE);
|
||||
mDialogWifiEntryKey = savedInstanceState.getString(SAVE_DIALOG_WIFIENTRY_KEY);
|
||||
|
||||
if (!TextUtils.isEmpty(mDialogWifiEntryKey)) {
|
||||
List<WifiEntry> wifiEntries = mWifiPickerTracker.getWifiEntries();
|
||||
Optional<WifiEntry> matchedWifiEntry = wifiEntries.stream().filter(wifiEntry ->
|
||||
TextUtils.equals(wifiEntry.getKey(), mDialogWifiEntryKey)).findAny();
|
||||
if (matchedWifiEntry.isPresent()) {
|
||||
mDialogWifiEntry = matchedWifiEntry.get();
|
||||
} else {
|
||||
throw new IllegalStateException("Failed to restore WifiEntry of key: "
|
||||
+ mDialogWifiEntryKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -283,7 +337,7 @@ public class WifiSettings2 extends RestrictedSettingsFragment
|
||||
mWifiEnabler.teardownSwitchController();
|
||||
}
|
||||
mWorkerThread.quit();
|
||||
|
||||
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@@ -361,6 +415,16 @@ public class WifiSettings2 extends RestrictedSettingsFragment
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if (requestCode == CONFIG_NETWORK_REQUEST) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
final WifiConfiguration wifiConfiguration = data.getParcelableExtra(
|
||||
ConfigureWifiEntryFragment.NETWORK_CONFIG_KEY);
|
||||
if (wifiConfiguration != null) {
|
||||
mWifiManager.save(wifiConfiguration,
|
||||
new WifiSaveThenConnectActionListener(wifiConfiguration));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean formerlyRestricted = mIsRestricted;
|
||||
@@ -384,17 +448,73 @@ public class WifiSettings2 extends RestrictedSettingsFragment
|
||||
return SettingsEnums.WIFI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
// If dialog has been shown, save its state.
|
||||
if (mDialog != null) {
|
||||
outState.putInt(SAVE_DIALOG_MODE, mDialogMode);
|
||||
outState.putString(SAVE_DIALOG_WIFIENTRY_KEY, mDialogWifiEntryKey);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo info) {
|
||||
// TODO(b/70983952): Add context menu options here. This should be driven by the appropriate
|
||||
// "can do action" APIs from WifiEntry.
|
||||
Preference preference = (Preference) view.getTag();
|
||||
if (!(preference instanceof LongPressWifiEntryPreference)) {
|
||||
// Do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache the WifiEntry for onContextItemSelected. Don't use it in other methods.
|
||||
mSelectedWifiEntry = ((LongPressWifiEntryPreference) preference).getWifiEntry();
|
||||
|
||||
menu.setHeaderTitle(mSelectedWifiEntry.getTitle());
|
||||
if (mSelectedWifiEntry.canConnect()) {
|
||||
menu.add(Menu.NONE, MENU_ID_CONNECT, 0 /* order */, R.string.wifi_connect);
|
||||
}
|
||||
|
||||
if (mSelectedWifiEntry.canDisconnect()) {
|
||||
menu.add(Menu.NONE, MENU_ID_DISCONNECT, 0 /* order */,
|
||||
R.string.wifi_disconnect_button_text);
|
||||
}
|
||||
|
||||
// "forget" for normal saved network. And "disconnect" for ephemeral network because it
|
||||
// could only be disconnected and be put in blacklists so it won't be used again.
|
||||
if (mSelectedWifiEntry.canForget()) {
|
||||
menu.add(Menu.NONE, MENU_ID_FORGET, 0 /* order */, R.string.forget);
|
||||
}
|
||||
|
||||
WifiConfiguration config = mSelectedWifiEntry.getWifiConfiguration();
|
||||
// Some configs are ineditable
|
||||
if (WifiUtils.isNetworkLockedDown(getActivity(), config)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSelectedWifiEntry.isSaved() && mSelectedWifiEntry.getConnectedState()
|
||||
!= WifiEntry.CONNECTED_STATE_CONNECTED) {
|
||||
menu.add(Menu.NONE, MENU_ID_MODIFY, 0 /* order */, R.string.wifi_modify);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
// TODO(b/70983952): Add context menu selection logic here. This should simply call the
|
||||
// appropriate WifiEntry action APIs (connect, forget, disconnect, etc).
|
||||
return false;
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ID_CONNECT:
|
||||
connect(mSelectedWifiEntry, true /* editIfNoConfig */, false /* fullScreenEdit */);
|
||||
return true;
|
||||
case MENU_ID_DISCONNECT:
|
||||
mSelectedWifiEntry.disconnect();
|
||||
return true;
|
||||
case MENU_ID_FORGET:
|
||||
forget(mSelectedWifiEntry);
|
||||
return true;
|
||||
case MENU_ID_MODIFY:
|
||||
showDialog(mSelectedWifiEntry, WifiConfigUiBase2.MODE_MODIFY);
|
||||
return true;
|
||||
default:
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -405,12 +525,10 @@ public class WifiSettings2 extends RestrictedSettingsFragment
|
||||
return super.onPreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
// TODO(b/70983952) Add WifiEntry click logic. This should be as simple as calling
|
||||
// WifiEntry.connect().
|
||||
if (preference instanceof LongPressWifiEntryPreference) {
|
||||
final WifiEntry selectedEntry =
|
||||
((LongPressWifiEntryPreference) preference).getWifiEntry();
|
||||
selectedEntry.connect();
|
||||
connect(selectedEntry, true /* editIfNoConfig */, true /* fullScreenEdit */);
|
||||
} else if (preference == mAddWifiNetworkPreference) {
|
||||
onAddNetworkPressed();
|
||||
} else {
|
||||
@@ -419,6 +537,54 @@ public class WifiSettings2 extends RestrictedSettingsFragment
|
||||
return true;
|
||||
}
|
||||
|
||||
private void showDialog(WifiEntry wifiEntry, int dialogMode) {
|
||||
if (WifiUtils.isNetworkLockedDown(getActivity(), wifiEntry.getWifiConfiguration())
|
||||
&& wifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED) {
|
||||
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(),
|
||||
RestrictedLockUtilsInternal.getDeviceOwner(getActivity()));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDialog != null) {
|
||||
removeDialog(WIFI_DIALOG_ID);
|
||||
mDialog = null;
|
||||
}
|
||||
|
||||
// Save the access point and edit mode
|
||||
mDialogWifiEntry = wifiEntry;
|
||||
mDialogWifiEntryKey = wifiEntry.getKey();
|
||||
mDialogMode = dialogMode;
|
||||
|
||||
showDialog(WIFI_DIALOG_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(int dialogId) {
|
||||
switch (dialogId) {
|
||||
case WIFI_DIALOG_ID:
|
||||
// modify network
|
||||
mDialog = WifiDialog2
|
||||
.createModal(getActivity(), this, mDialogWifiEntry, mDialogMode);
|
||||
return mDialog;
|
||||
default:
|
||||
return super.onCreateDialog(dialogId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogShowing() {
|
||||
super.onDialogShowing();
|
||||
setOnDismissListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
// We don't keep any dialog object when dialog was dismissed.
|
||||
mDialog = null;
|
||||
mDialogWifiEntry = null;
|
||||
mDialogWifiEntryKey = null;
|
||||
}
|
||||
|
||||
/** Called when the state of Wifi has changed. */
|
||||
@Override
|
||||
public void onWifiStateChanged() {
|
||||
@@ -584,7 +750,8 @@ public class WifiSettings2 extends RestrictedSettingsFragment
|
||||
.launch();
|
||||
}
|
||||
|
||||
private LongPressWifiEntryPreference createLongPressWifiEntryPreference(WifiEntry wifiEntry) {
|
||||
@VisibleForTesting
|
||||
LongPressWifiEntryPreference createLongPressWifiEntryPreference(WifiEntry wifiEntry) {
|
||||
return new LongPressWifiEntryPreference(getPrefContext(), wifiEntry, this);
|
||||
}
|
||||
|
||||
@@ -715,6 +882,88 @@ public class WifiSettings2 extends RestrictedSettingsFragment
|
||||
return R.string.help_url_wifi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onForget(WifiDialog2 dialog) {
|
||||
forget(mDialogWifiEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubmit(WifiDialog2 dialog) {
|
||||
final int dialogMode = mDialog.getController().getMode();
|
||||
|
||||
if (dialogMode == WifiConfigUiBase2.MODE_MODIFY) {
|
||||
mWifiManager.save(mDialogWifiEntry.getWifiConfiguration(), mSaveListener);
|
||||
} else if (dialogMode == WifiConfigUiBase2.MODE_CONNECT
|
||||
|| (dialogMode == WifiConfigUiBase2.MODE_VIEW && mDialogWifiEntry.canConnect())) {
|
||||
connect(mDialogWifiEntry, false /* editIfNoConfig */, false /* fullScreenEdit*/);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScan(WifiDialog2 dialog, String ssid) {
|
||||
// Launch QR code scanner to join a network.
|
||||
startActivityForResult(WifiDppUtils.getEnrolleeQrCodeScannerIntent(ssid),
|
||||
REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER);
|
||||
}
|
||||
|
||||
private void forget(WifiEntry wifiEntry) {
|
||||
mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_WIFI_FORGET);
|
||||
wifiEntry.forget();
|
||||
}
|
||||
|
||||
private void connect(WifiEntry wifiEntry, boolean editIfNoConfig, boolean fullScreenEdit) {
|
||||
mMetricsFeatureProvider.action(getActivity(), SettingsEnums.ACTION_WIFI_CONNECT,
|
||||
wifiEntry.isSaved());
|
||||
|
||||
// If it's an unsaved secure WifiEntry, it will callback
|
||||
// WifiEntryCallback#onConnectResult with
|
||||
// WifiEntryCallback#CONNECT_STATUS_FAILURE_NO_CONFIG
|
||||
wifiEntry.setListener(new WifiEntryConnectCallback(wifiEntry, editIfNoConfig,
|
||||
fullScreenEdit));
|
||||
wifiEntry.connect();
|
||||
}
|
||||
|
||||
private class WifiSaveThenConnectActionListener implements WifiManager.ActionListener {
|
||||
final WifiConfiguration mWifiConfiguration;
|
||||
|
||||
WifiSaveThenConnectActionListener(WifiConfiguration wifiConfiguration) {
|
||||
mWifiConfiguration = wifiConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
mWifiManager.connect(mWifiConfiguration, new WifiConnectActionListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int reason) {
|
||||
final Activity activity = getActivity();
|
||||
if (isFisishingOrDestroyed(activity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.makeText(activity, R.string.wifi_failed_save_message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
};
|
||||
|
||||
private class WifiConnectActionListener implements WifiManager.ActionListener {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int reason) {
|
||||
final Activity activity = getActivity();
|
||||
if (isFisishingOrDestroyed(activity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.makeText(activity, R.string.wifi_failed_connect_message, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
};
|
||||
|
||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||
new BaseSearchIndexProvider() {
|
||||
@Override
|
||||
@@ -736,4 +985,72 @@ public class WifiSettings2 extends RestrictedSettingsFragment
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
private class WifiEntryConnectCallback implements WifiEntryCallback {
|
||||
final WifiEntry mConnectWifiEntry;
|
||||
final boolean mEditIfNoConfig;
|
||||
final boolean mFullScreenEdit;
|
||||
|
||||
WifiEntryConnectCallback(WifiEntry connectWifiEntry, boolean editIfNoConfig,
|
||||
boolean fullScreenEdit) {
|
||||
mConnectWifiEntry = connectWifiEntry;
|
||||
mEditIfNoConfig = editIfNoConfig;
|
||||
mFullScreenEdit = fullScreenEdit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdated() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectResult(@ConnectStatus int status) {
|
||||
final Activity activity = getActivity();
|
||||
if (isFisishingOrDestroyed(activity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (status == WifiEntryCallback.CONNECT_STATUS_FAILURE_NO_CONFIG) {
|
||||
if (mEditIfNoConfig) {
|
||||
// Edit an unsaved secure Wi-Fi network.
|
||||
if (mFullScreenEdit) {
|
||||
final Bundle bundle = new Bundle();
|
||||
bundle.putString(WifiNetworkDetailsFragment2.KEY_CHOSEN_WIFIENTRY_KEY,
|
||||
mConnectWifiEntry.getKey());
|
||||
new SubSettingLauncher(getContext())
|
||||
.setTitleText(mConnectWifiEntry.getTitle())
|
||||
.setDestination(ConfigureWifiEntryFragment.class.getName())
|
||||
.setArguments(bundle)
|
||||
.setSourceMetricsCategory(getMetricsCategory())
|
||||
.setResultListener(WifiSettings2.this, CONFIG_NETWORK_REQUEST)
|
||||
.launch();
|
||||
} else {
|
||||
showDialog(mConnectWifiEntry, WifiConfigUiBase2.MODE_MODIFY);
|
||||
}
|
||||
}
|
||||
} else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) {
|
||||
Toast.makeText(getContext(), R.string.wifi_failed_connect_message,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnectResult(@DisconnectStatus int status) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onForgetResult(@ForgetStatus int status) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSignInResult(@SignInStatus int status) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFisishingOrDestroyed(Activity activity) {
|
||||
return activity == null || activity.isFinishing() || activity.isDestroyed();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user