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.WifiConfiguration;
import android.net.wifi.WifiInfo; import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.CountDownTimer;
import android.os.Handler; import android.os.Handler;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.FeatureFlagUtils; import android.util.FeatureFlagUtils;
@@ -84,6 +85,7 @@ import java.net.Inet4Address;
import java.net.Inet6Address; import java.net.Inet6Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.time.Duration;
import java.util.StringJoiner; import java.util.StringJoiner;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -127,6 +129,19 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
@VisibleForTesting @VisibleForTesting
static final String KEY_IPV6_ADDRESSES_PREF = "ipv6_addresses"; 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 AccessPoint mAccessPoint;
private final ConnectivityManager mConnectivityManager; private final ConnectivityManager mConnectivityManager;
private final Fragment mFragment; private final Fragment mFragment;
@@ -143,6 +158,9 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
private final WifiTracker mWifiTracker; private final WifiTracker mWifiTracker;
private final MetricsFeatureProvider mMetricsFeatureProvider; private final MetricsFeatureProvider mMetricsFeatureProvider;
private boolean mIsOutOfRange; private boolean mIsOutOfRange;
private boolean mConnected;
private int mConnectingState;
private WifiManager.ActionListener mConnectListener;
// UI elements - in order of appearance // UI elements - in order of appearance
private ActionButtonsPreference mButtonsPref; private ActionButtonsPreference mButtonsPref;
@@ -182,7 +200,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
// fall through // fall through
case WifiManager.NETWORK_STATE_CHANGED_ACTION: case WifiManager.NETWORK_STATE_CHANGED_ACTION:
case WifiManager.RSSI_CHANGED_ACTION: case WifiManager.RSSI_CHANGED_ACTION:
updateNetworkInfo(); refreshPage();
break; break;
} }
} }
@@ -197,7 +215,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
public void onLinkPropertiesChanged(Network network, LinkProperties lp) { public void onLinkPropertiesChanged(Network network, LinkProperties lp) {
if (network.equals(mNetwork) && !lp.equals(mLinkProperties)) { if (network.equals(mNetwork) && !lp.equals(mLinkProperties)) {
mLinkProperties = lp; mLinkProperties = lp;
updateIpLayerInfo(); refreshIpLayerInfo();
} }
} }
@@ -224,12 +242,17 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
} }
mNetworkCapabilities = nc; mNetworkCapabilities = nc;
refreshButtons(); refreshButtons();
updateIpLayerInfo(); refreshIpLayerInfo();
} }
} }
@Override @Override
public void onLost(Network network) { 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)) { if (network.equals(mNetwork)) {
exitActivity(); exitActivity();
} }
@@ -240,13 +263,23 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
/** Called when the state of Wifi has changed. */ /** Called when the state of Wifi has changed. */
public void onWifiStateChanged(int state) { public void onWifiStateChanged(int state) {
Log.d(TAG, "onWifiStateChanged(" + 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. */ /** Called when the connection state of wifi has changed. */
public void onConnectedChanged() { public void onConnectedChanged() {
Log.d(TAG, "onConnectedChanged"); updateAccessPointFromScannedList();
// Do nothing. 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. * {@link WifiTracker#getAccessPoints()} should be called to get the updated list.
*/ */
public void onAccessPointsChanged() { public void onAccessPointsChanged() {
Log.d(TAG, "onAccessPointsChanged"); refreshPage();
updateNetworkInfo();
} }
}; };
@@ -314,6 +346,19 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
} else { } else {
mWifiTracker = null; 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 @Override
@@ -339,10 +384,14 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
.setButton1OnClickListener(view -> forgetNetwork()) .setButton1OnClickListener(view -> forgetNetwork())
.setButton2Text(R.string.wifi_sign_in_button_text) .setButton2Text(R.string.wifi_sign_in_button_text)
.setButton2OnClickListener(view -> signIntoNetwork()) .setButton2OnClickListener(view -> signIntoNetwork())
.setButton3Text(R.string.share) .setButton3Text(R.string.wifi_connect)
.setButton3Icon(R.drawable.ic_qrcode_24dp) .setButton3Icon(R.drawable.ic_settings_wireless)
.setButton3OnClickListener(view -> shareNetwork()) .setButton3OnClickListener(view -> connectNetwork())
.setButton3Visible(WifiDppUtils.isSupportConfiguratorQrCodeGenerator(mAccessPoint)); .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); mSignalStrengthPref = screen.findPreference(KEY_SIGNAL_STRENGTH_PREF);
mTxLinkSpeedPref = screen.findPreference(KEY_TX_LINK_SPEED); 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 @Override
public void onResume() { public void onResume() {
// Ensure mNetwork is set before any callbacks above are delivered, since our // Ensure mNetwork is set before any callbacks above are delivered, since our
// NetworkCallback only looks at changes to mNetwork. // NetworkCallback only looks at changes to mNetwork.
mNetwork = mWifiManager.getCurrentNetwork();
mLinkProperties = mConnectivityManager.getLinkProperties(mNetwork);
mNetworkCapabilities = mConnectivityManager.getNetworkCapabilities(mNetwork);
updateNetworkInfo(); updateNetworkInfo();
refreshPage();
mContext.registerReceiver(mReceiver, mFilter); mContext.registerReceiver(mReceiver, mFilter);
mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback, mConnectivityManager.registerNetworkCallback(mNetworkRequest, mNetworkCallback,
mHandler); mHandler);
@@ -421,11 +474,13 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
} }
private void updateNetworkInfo() { private void refreshPage() {
if(!updateAccessPoint()) { if(!updateAccessPoint()) {
return; return;
} }
Log.d(TAG, "Update UI!");
// refresh header // refresh header
refreshEntityHeader(); refreshEntityHeader();
@@ -441,26 +496,37 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
// Receive Link Speed Pref // Receive Link Speed Pref
refreshRxSpeed(); refreshRxSpeed();
// IP related information // IP related information
updateIpLayerInfo(); refreshIpLayerInfo();
// MAC Address Pref // MAC Address Pref
refreshMacAddress(); refreshMacAddress();
} }
private boolean updateAccessPoint() { private boolean updateAccessPoint() {
boolean changed = false; boolean changed = false;
if (mWifiTracker != null) { if (mWifiTracker != null) {
// remember mIsOutOfRange as old before updated
boolean oldState = mIsOutOfRange;
updateAccessPointFromScannedList(); updateAccessPointFromScannedList();
// refresh UI if signal level changed for disconnect network. // refresh UI if signal level changed for disconnect network.
changed = mRssiSignalLevel != mAccessPoint.getLevel(); changed = mRssiSignalLevel != mAccessPoint.getLevel();
changed |= oldState != mIsOutOfRange;
} }
if (mAccessPoint.isActive()) { if (mAccessPoint.isActive()) {
// No need to fetch LinkProperties and NetworkCapabilities, they are updated by the // Sometimes {@link WifiManager#getCurrentNetwork()} return null after connected,
// callbacks. mNetwork doesn't change except in onResume. // refresh it if needed.
if (mNetwork == null) {
updateNetworkInfo();
}
mNetworkInfo = mConnectivityManager.getNetworkInfo(mNetwork); mNetworkInfo = mConnectivityManager.getNetworkInfo(mNetwork);
mWifiInfo = mWifiManager.getConnectionInfo(); mWifiInfo = mWifiManager.getConnectionInfo();
if (mNetwork == null || mNetworkInfo == null || mWifiInfo == null) { 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(); exitActivity();
return false; return false;
} }
@@ -474,6 +540,8 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
} }
private void updateAccessPointFromScannedList() { private void updateAccessPointFromScannedList() {
if (mWifiTracker == null) return;
mIsOutOfRange = true; mIsOutOfRange = true;
if (mAccessPoint.getConfig() == null) { if (mAccessPoint.getConfig() == null) {
@@ -484,7 +552,7 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
if (ap.getConfig() != null if (ap.getConfig() != null
&& mAccessPoint.matches(ap.getConfig())) { && mAccessPoint.matches(ap.getConfig())) {
mAccessPoint = ap; mAccessPoint = ap;
mIsOutOfRange = false; mIsOutOfRange = !mAccessPoint.isReachable();
return; return;
} }
} }
@@ -543,6 +611,11 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
band = mContext.getResources().getString(R.string.wifi_band_5ghz); band = mContext.getResources().getString(R.string.wifi_band_5ghz);
} else { } else {
Log.e(TAG, "Unexpected frequency " + frequency); 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.setSummary(band);
mFrequencyPref.setVisible(true); mFrequencyPref.setVisible(true);
@@ -616,12 +689,21 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
private void refreshButtons() { private void refreshButtons() {
mButtonsPref.setButton1Visible(canForgetNetwork()); mButtonsPref.setButton1Visible(canForgetNetwork());
mButtonsPref.setButton2Visible(canSignIntoNetwork()); mButtonsPref.setButton2Visible(canSignIntoNetwork());
mButtonsPref.setButton3Visible(canShareNetwork()); mButtonsPref.setButton3Visible(canConnectNetwork());
mButtonsPref.setVisible( mButtonsPref.setButton4Visible(canShareNetwork());
canSignIntoNetwork() || canForgetNetwork() || 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. // Hide IP layer info if not a connected network.
if (!mAccessPoint.isActive() || mNetwork == null || mLinkProperties == null) { if (!mAccessPoint.isActive() || mNetwork == null || mLinkProperties == null) {
mIpAddressPref.setVisible(false); mIpAddressPref.setVisible(false);
@@ -823,4 +905,169 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController
private boolean usingDataUsageHeader(Context context) { private boolean usingDataUsageHeader(Context context) {
return FeatureFlagUtils.isEnabled(context, FeatureFlags.WIFI_DETAILS_DATAUSAGE_HEADER); 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;
}
} }