Provide connect button in Wi-Fi detail page

User can click connect button to connect this AP at the detail page even
the Wi-Fi disabled. Would turn on Wi-Fi if disabled and then connect to
this saved network.

Bug: 126503889
Test: atest and manual test
Change-Id: I313e290474d6623a6c3e84027e81d0d1ebf16919
This commit is contained in:
clownshen
2019-03-22 23:59:25 +08:00
parent dedeb2bd18
commit 936f1f215e

View File

@@ -41,6 +41,7 @@ import android.net.RouteInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.CountDownTimer;
import android.os.Handler;
import android.text.TextUtils;
import android.util.FeatureFlagUtils;
@@ -84,6 +85,7 @@ import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.Duration;
import java.util.StringJoiner;
import java.util.stream.Collectors;
@@ -127,6 +129,19 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
@VisibleForTesting
static final String KEY_IPV6_ADDRESSES_PREF = "ipv6_addresses";
private static final int STATE_NONE = 1;
private static final int STATE_ENABLE_WIFI = 2;
private static final int STATE_ENABLE_WIFI_FAILED = 3;
private static final int STATE_CONNECTING = 4;
private static final int STATE_CONNECTED = 5;
private static final int STATE_FAILED = 6;
private static final int STATE_NOT_IN_RANGE = 7;
private static final int STATE_DISCONNECTED = 8;
private static final long TIMEOUT = Duration.ofSeconds(10).toMillis();
// Be static to avoid too much object not be reset.
private static CountDownTimer mTimer;
private AccessPoint mAccessPoint;
private final ConnectivityManager mConnectivityManager;
private final Fragment mFragment;
@@ -143,6 +158,9 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
private final WifiTracker mWifiTracker;
private final MetricsFeatureProvider mMetricsFeatureProvider;
private boolean mIsOutOfRange;
private boolean mConnected;
private int mConnectingState;
private WifiManager.ActionListener mConnectListener;
// UI elements - in order of appearance
private ActionButtonsPreference mButtonsPref;
@@ -182,7 +200,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
// fall through
case WifiManager.NETWORK_STATE_CHANGED_ACTION:
case WifiManager.RSSI_CHANGED_ACTION:
updateNetworkInfo();
refreshPage();
break;
}
}
@@ -197,7 +215,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
public void onLinkPropertiesChanged(Network network, LinkProperties lp) {
if (network.equals(mNetwork) && !lp.equals(mLinkProperties)) {
mLinkProperties = lp;
updateIpLayerInfo();
refreshIpLayerInfo();
}
}
@@ -224,12 +242,17 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
}
mNetworkCapabilities = nc;
refreshButtons();
updateIpLayerInfo();
refreshIpLayerInfo();
}
}
@Override
public void onLost(Network network) {
// If support detail page for saved network, should update as disconnect but not exit.
if (SavedAccessPointsWifiSettings.usingDetailsFragment(mContext)) {
return;
}
if (network.equals(mNetwork)) {
exitActivity();
}
@@ -240,13 +263,23 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
/** Called when the state of Wifi has changed. */
public void onWifiStateChanged(int state) {
Log.d(TAG, "onWifiStateChanged(" + state + ")");
// Do nothing.
if (mConnectingState == STATE_ENABLE_WIFI && state == WifiManager.WIFI_STATE_ENABLED) {
updateConnectingState(STATE_CONNECTING);
}
}
/** Called when the connection state of wifi has changed. */
public void onConnectedChanged() {
Log.d(TAG, "onConnectedChanged");
// Do nothing.
updateAccessPointFromScannedList();
if (mConnected != mAccessPoint.isActive()) {
Log.d(TAG, "Connection state changed!");
mConnected = mAccessPoint.isActive();
if (mAccessPoint.isActive()) {
updateConnectingState(STATE_CONNECTED);
} else {
updateConnectingState(STATE_DISCONNECTED);
}
}
}
/**
@@ -254,8 +287,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
* {@link WifiTracker#getAccessPoints()} should be called to get the updated list.
*/
public void onAccessPointsChanged() {
Log.d(TAG, "onAccessPointsChanged");
updateNetworkInfo();
refreshPage();
}
};
@@ -314,6 +346,19 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
} else {
mWifiTracker = null;
}
mConnected = mAccessPoint.isActive();
mConnectingState = STATE_NONE;
mConnectListener = new WifiManager.ActionListener() {
@Override
public void onSuccess() {
// Do nothing
}
@Override
public void onFailure(int reason) {
updateConnectingState(STATE_FAILED);
}
};
}
@Override
@@ -339,10 +384,14 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
.setButton1OnClickListener(view -> forgetNetwork())
.setButton2Text(R.string.wifi_sign_in_button_text)
.setButton2OnClickListener(view -> signIntoNetwork())
.setButton3Text(R.string.share)
.setButton3Icon(R.drawable.ic_qrcode_24dp)
.setButton3OnClickListener(view -> shareNetwork())
.setButton3Visible(WifiDppUtils.isSupportConfiguratorQrCodeGenerator(mAccessPoint));
.setButton3Text(R.string.wifi_connect)
.setButton3Icon(R.drawable.ic_settings_wireless)
.setButton3OnClickListener(view -> connectNetwork())
.setButton3Enabled(true)
.setButton4Text(R.string.share)
.setButton4Icon(R.drawable.ic_qrcode_24dp)
.setButton4OnClickListener(view -> shareNetwork())
.setButton4Visible(WifiDppUtils.isSupportConfiguratorQrCodeGenerator(mAccessPoint));
mSignalStrengthPref = screen.findPreference(KEY_SIGNAL_STRENGTH_PREF);
mTxLinkSpeedPref = screen.findPreference(KEY_TX_LINK_SPEED);
@@ -397,14 +446,18 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
}
}
private void updateNetworkInfo() {
mNetwork = mWifiManager.getCurrentNetwork();
mLinkProperties = mConnectivityManager.getLinkProperties(mNetwork);
mNetworkCapabilities = mConnectivityManager.getNetworkCapabilities(mNetwork);
}
@Override
public void onResume() {
// Ensure mNetwork is set before any callbacks above are delivered, since our
// NetworkCallback only looks at changes to mNetwork.
mNetwork = mWifiManager.getCurrentNetwork();
mLinkProperties = mConnectivityManager.getLinkProperties(mNetwork);
mNetworkCapabilities = mConnectivityManager.getNetworkCapabilities(mNetwork);
updateNetworkInfo();
refreshPage();
mContext.registerReceiver(mReceiver, mFilter);
mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback,
mHandler);
@@ -421,11 +474,13 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
}
private void updateNetworkInfo() {
private void refreshPage() {
if(!updateAccessPoint()) {
return;
}
Log.d(TAG, "Update UI!");
// refresh header
refreshEntityHeader();
@@ -441,26 +496,37 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
// Receive Link Speed Pref
refreshRxSpeed();
// IP related information
updateIpLayerInfo();
refreshIpLayerInfo();
// MAC Address Pref
refreshMacAddress();
}
private boolean updateAccessPoint() {
boolean changed = false;
if (mWifiTracker != null) {
// remember mIsOutOfRange as old before updated
boolean oldState = mIsOutOfRange;
updateAccessPointFromScannedList();
// refresh UI if signal level changed for disconnect network.
changed = mRssiSignalLevel != mAccessPoint.getLevel();
changed |= oldState != mIsOutOfRange;
}
if (mAccessPoint.isActive()) {
// No need to fetch LinkProperties and NetworkCapabilities, they are updated by the
// callbacks. mNetwork doesn't change except in onResume.
// Sometimes {@link WifiManager#getCurrentNetwork()} return null after connected,
// refresh it if needed.
if (mNetwork == null) {
updateNetworkInfo();
}
mNetworkInfo = mConnectivityManager.getNetworkInfo(mNetwork);
mWifiInfo = mWifiManager.getConnectionInfo();
if (mNetwork == null || mNetworkInfo == null || mWifiInfo == null) {
// Once connected, can't get mNetworkInfo immediately, return false and wait for
// next time to update UI.
if (SavedAccessPointsWifiSettings.usingDetailsFragment(mContext)) {
return false;
}
exitActivity();
return false;
}
@@ -474,6 +540,8 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
}
private void updateAccessPointFromScannedList() {
if (mWifiTracker == null) return;
mIsOutOfRange = true;
if (mAccessPoint.getConfig() == null) {
@@ -484,7 +552,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
if (ap.getConfig() != null
&& mAccessPoint.matches(ap.getConfig())) {
mAccessPoint = ap;
mIsOutOfRange = false;
mIsOutOfRange = !mAccessPoint.isReachable();
return;
}
}
@@ -543,6 +611,11 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
band = mContext.getResources().getString(R.string.wifi_band_5ghz);
} else {
Log.e(TAG, "Unexpected frequency " + frequency);
// Connecting state is unstable, make it disappeared if unexpected
if (mConnectingState == STATE_CONNECTING) {
mFrequencyPref.setVisible(false);
}
return;
}
mFrequencyPref.setSummary(band);
mFrequencyPref.setVisible(true);
@@ -616,12 +689,21 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
private void refreshButtons() {
mButtonsPref.setButton1Visible(canForgetNetwork());
mButtonsPref.setButton2Visible(canSignIntoNetwork());
mButtonsPref.setButton3Visible(canShareNetwork());
mButtonsPref.setVisible(
canSignIntoNetwork() || canForgetNetwork() || canShareNetwork());
mButtonsPref.setButton3Visible(canConnectNetwork());
mButtonsPref.setButton4Visible(canShareNetwork());
mButtonsPref.setVisible(canSignIntoNetwork()
|| canForgetNetwork()
|| canShareNetwork()
|| canConnectNetwork());
}
private void updateIpLayerInfo() {
private boolean canConnectNetwork() {
// Display connect button for disconnected AP even not in the range.
return SavedAccessPointsWifiSettings.usingDetailsFragment(mContext)
&& !mAccessPoint.isActive();
}
private void refreshIpLayerInfo() {
// Hide IP layer info if not a connected network.
if (!mAccessPoint.isActive() || mNetwork == null || mLinkProperties == null) {
mIpAddressPref.setVisible(false);
@@ -823,4 +905,169 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
private boolean usingDataUsageHeader(Context context) {
return FeatureFlagUtils.isEnabled(context, FeatureFlags.WIFI_DETAILS_DATAUSAGE_HEADER);
}
private void connectNetwork() {
final Activity activity = mFragment.getActivity();
// error handling, connected/saved network should have mWifiConfig.
if (mWifiConfig == null) {
Toast.makeText(activity,
R.string.wifi_failed_connect_message,
Toast.LENGTH_SHORT).show();
return;
}
// init state before connect
mConnectingState = STATE_NONE;
if (mWifiManager.isWifiEnabled()) {
updateConnectingState(STATE_CONNECTING);
} else {
// Enable Wi-Fi automatically to connect AP
updateConnectingState(STATE_ENABLE_WIFI);
}
}
private void updateConnectingState(int state) {
final Activity activity = mFragment.getActivity();
Log.d(TAG, "updateConnectingState from " + mConnectingState + " to " + state);
switch (mConnectingState) {
case STATE_NONE:
case STATE_ENABLE_WIFI:
if (state == STATE_ENABLE_WIFI) {
Log.d(TAG, "Turn on Wi-Fi automatically!");
updateConnectedButton(STATE_ENABLE_WIFI);
Toast.makeText(activity,
R.string.wifi_turned_on_message,
Toast.LENGTH_SHORT).show();
mWifiManager.setWifiEnabled(true);
// start timer for error handling
startTimer();
} else if (state == STATE_CONNECTING) {
Log.d(TAG, "connecting...");
updateConnectedButton(STATE_CONNECTING);
mWifiManager.connect(mWifiConfig.networkId, mConnectListener);
// start timer for error handling since framework didn't call back if failed
startTimer();
} else if (state == STATE_ENABLE_WIFI_FAILED) {
Log.e(TAG, "Wi-Fi failed to enable network!");
stopTimer();
// reset state
state = STATE_NONE;
Toast.makeText(activity,
R.string.wifi_failed_connect_message,
Toast.LENGTH_SHORT).show();
updateConnectedButton(STATE_ENABLE_WIFI_FAILED);
}
// Do not break here for disconnected event.
case STATE_CONNECTED:
if (state == STATE_DISCONNECTED) {
Log.d(TAG, "disconnected");
// reset state
state = STATE_NONE;
updateConnectedButton(STATE_DISCONNECTED);
refreshPage();
// clear for getting MAC Address from saved configuration
mWifiInfo = null;
}
break;
case STATE_CONNECTING:
if (state == STATE_CONNECTED) {
Log.d(TAG, "connected");
stopTimer();
updateConnectedButton(STATE_CONNECTED);
Toast.makeText(activity,
mContext.getString(R.string.wifi_connected_to_message,
mAccessPoint.getTitle()),
Toast.LENGTH_SHORT).show();
updateNetworkInfo();
refreshPage();
} else if (state == STATE_NOT_IN_RANGE) {
Log.d(TAG, "AP not in range");
stopTimer();
// reset state
state = STATE_NONE;
Toast.makeText(activity,
R.string.wifi_not_in_range_message,
Toast.LENGTH_SHORT).show();
updateConnectedButton(STATE_NOT_IN_RANGE);
} else if (state == STATE_FAILED) {
Log.d(TAG, "failed");
stopTimer();
// reset state
state = STATE_NONE;
Toast.makeText(activity,
R.string.wifi_failed_connect_message,
Toast.LENGTH_SHORT).show();
updateConnectedButton(STATE_FAILED);
}
break;
default:
Log.e(TAG, "Invalid state : " + mConnectingState);
// don't update invalid state
return;
}
mConnectingState = state;
}
private void updateConnectedButton(int state) {
switch (state) {
case STATE_ENABLE_WIFI:
case STATE_CONNECTING:
mButtonsPref.setButton3Text(R.string.wifi_connecting)
.setButton3Enabled(false);
break;
case STATE_CONNECTED:
mButtonsPref.setButton3Visible(false);
break;
case STATE_DISCONNECTED:
case STATE_NOT_IN_RANGE:
case STATE_FAILED:
case STATE_ENABLE_WIFI_FAILED:
mButtonsPref.setButton3Text(R.string.wifi_connect)
.setButton3Icon(R.drawable.ic_settings_wireless)
.setButton3Enabled(true)
.setButton3Visible(true);
break;
default:
Log.e(TAG, "Invalid connect button state : " + state);
break;
}
}
private void startTimer() {
if (mTimer != null) {
stopTimer();
}
mTimer = new CountDownTimer(TIMEOUT, TIMEOUT + 1) {
@Override
public void onTick(long millisUntilFinished) {
// Do nothing
}
@Override
public void onFinish() {
Log.e(TAG, "Timeout for state:" + mConnectingState);
if (mConnectingState == STATE_ENABLE_WIFI) {
updateConnectingState(STATE_ENABLE_WIFI_FAILED);
} else if (mConnectingState == STATE_CONNECTING) {
updateAccessPointFromScannedList();
if (mIsOutOfRange) {
updateConnectingState(STATE_NOT_IN_RANGE);
} else {
updateConnectingState(STATE_FAILED);
}
}
}
};
mTimer.start();
}
private void stopTimer() {
if (mTimer == null) return;
mTimer.cancel();
mTimer = null;
}
}