Implement Wi-Fi DPP flow

1. Wi-Fi DPP hanshake fail UI
2. Show Wi-Fi DPP QR code information field on WifiDppAddDeviceFragment if it's available.
3. Click 'Choose Different Network' button will show WifiDppChooseSavedWifiNetworkFragment
4. After QR code scanner scans success, WifiDppConfiguratorActivity caches WifiQrCode instead
   of just a QR code string

Bug: 122429170
Test: manual test
Change-Id: I1ce1b014ff86903b5a7a8f3575cc98eb1079583c
This commit is contained in:
Arc Wang
2019-01-09 11:54:38 +08:00
parent 7a14f706e1
commit a7d51370c8
7 changed files with 92 additions and 53 deletions

View File

@@ -2104,6 +2104,12 @@
<string name="wifi_dpp_add_another_device">Add another device</string> <string name="wifi_dpp_add_another_device">Add another device</string>
<!-- Button label to choose different Wi-Fi network [CHAR LIMIT=80] --> <!-- Button label to choose different Wi-Fi network [CHAR LIMIT=80] -->
<string name="wifi_dpp_choose_different_network">Choose different network</string> <string name="wifi_dpp_choose_different_network">Choose different network</string>
<!-- Hint for QR code detection [CHAR LIMIT=50] -->
<string name="wifi_dpp_could_not_add_device">Couldn\u2019t add device</string>
<!-- Title for the fragment to show that device found but naming known [CHAR LIMIT=50] -->
<string name="wifi_dpp_device_found">Device found</string>
<!-- Label for the try again button [CHAR LIMIT=20]-->
<string name="retry">Retry</string>
<!-- Label for the check box to share a network with other users on the same device --> <!-- Label for the check box to share a network with other users on the same device -->
<string name="wifi_shared">Share with other device users</string> <string name="wifi_shared">Share with other device users</string>
<!-- Hint for unchanged fields --> <!-- Hint for unchanged fields -->

View File

@@ -21,6 +21,7 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -55,6 +56,7 @@ public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment {
// Update success UI. // Update success UI.
mTitle.setText(R.string.wifi_dpp_wifi_shared_with_device); mTitle.setText(R.string.wifi_dpp_wifi_shared_with_device);
mSummary.setVisibility(View.INVISIBLE); mSummary.setVisibility(View.INVISIBLE);
mChooseDifferentNetwork.setVisibility(View.INVISIBLE);
mButtonLeft.setText(R.string.wifi_dpp_add_another_device); mButtonLeft.setText(R.string.wifi_dpp_add_another_device);
mButtonLeft.setOnClickListener(v -> getFragmentManager().popBackStack()); mButtonLeft.setOnClickListener(v -> getFragmentManager().popBackStack());
mButtonRight.setText(R.string.done); mButtonRight.setText(R.string.done);
@@ -63,8 +65,13 @@ public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment {
@Override @Override
public void onFailure(int code) { public void onFailure(int code) {
//TODO(b/122429170): Show DPP configuration error state UI
Log.d(TAG, "DppStatusCallback.onFailure " + code); Log.d(TAG, "DppStatusCallback.onFailure " + code);
// Update fail UI.
mTitle.setText(R.string.wifi_dpp_could_not_add_device);
mSummary.setVisibility(View.INVISIBLE);
mChooseDifferentNetwork.setVisibility(View.INVISIBLE);
mButtonRight.setText(R.string.retry);
} }
@Override @Override
@@ -99,6 +106,15 @@ public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment {
public void onViewCreated(View view, Bundle savedInstanceState) { public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
final WifiQrCode wifiQrCode = ((WifiDppConfiguratorActivity) getActivity())
.getWifiDppQrCode();
final String information = wifiQrCode.getInformation();
if (TextUtils.isEmpty(information)) {
mTitle.setText(R.string.wifi_dpp_device_found);
} else {
mTitle.setText(information);
}
final WifiNetworkConfig wifiNetworkConfig = ((WifiDppConfiguratorActivity) getActivity()) final WifiNetworkConfig wifiNetworkConfig = ((WifiDppConfiguratorActivity) getActivity())
.getWifiNetworkConfig(); .getWifiNetworkConfig();
if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) { if (!WifiNetworkConfig.isValidConfig(wifiNetworkConfig)) {
@@ -110,7 +126,8 @@ public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment {
mWifiApPictureView = view.findViewById(R.id.wifi_ap_picture_view); mWifiApPictureView = view.findViewById(R.id.wifi_ap_picture_view);
mChooseDifferentNetwork = view.findViewById(R.id.choose_different_network); mChooseDifferentNetwork = view.findViewById(R.id.choose_different_network);
mChooseDifferentNetwork.setOnClickListener(v -> getFragmentManager().popBackStack()); mChooseDifferentNetwork.setOnClickListener(v ->
mClickChooseDifferentNetworkListener.onClickChooseDifferentNetwork());
mButtonLeft = view.findViewById(R.id.button_left); mButtonLeft = view.findViewById(R.id.button_left);
mButtonLeft.setText(R.string.cancel); mButtonLeft.setText(R.string.cancel);
@@ -125,11 +142,34 @@ public class WifiDppAddDeviceFragment extends WifiDppQrCodeBaseFragment {
} }
private void startWifiDppInitiator() { private void startWifiDppInitiator() {
final String enrolleeUri = ((WifiDppConfiguratorActivity) getActivity()).getDppUri(); final WifiQrCode wifiQrCode = ((WifiDppConfiguratorActivity) getActivity())
.getWifiDppQrCode();
final String qrCode = wifiQrCode.getQrCode();
final int networkId = final int networkId =
((WifiDppConfiguratorActivity) getActivity()).getWifiNetworkConfig().getNetworkId(); ((WifiDppConfiguratorActivity) getActivity()).getWifiNetworkConfig().getNetworkId();
final WifiManager wifiManager = getContext().getSystemService(WifiManager.class); final WifiManager wifiManager = getContext().getSystemService(WifiManager.class);
wifiManager.startDppAsConfiguratorInitiator(enrolleeUri, networkId,
wifiManager.startDppAsConfiguratorInitiator(qrCode, networkId,
WifiManager.DPP_NETWORK_ROLE_STA, /* handler */ null, new DppStatusCallback()); WifiManager.DPP_NETWORK_ROLE_STA, /* handler */ null, new DppStatusCallback());
} }
// Container Activity must implement this interface
public interface OnClickChooseDifferentNetworkListener {
public void onClickChooseDifferentNetwork();
}
OnClickChooseDifferentNetworkListener mClickChooseDifferentNetworkListener;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mClickChooseDifferentNetworkListener = (OnClickChooseDifferentNetworkListener) context;
}
@Override
public void onDetach() {
mClickChooseDifferentNetworkListener = null;
super.onDetach();
}
} }

View File

@@ -51,7 +51,8 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
WifiNetworkConfig.Retriever, WifiNetworkConfig.Retriever,
WifiDppQrCodeGeneratorFragment.OnQrCodeGeneratorFragmentAddButtonClickedListener, WifiDppQrCodeGeneratorFragment.OnQrCodeGeneratorFragmentAddButtonClickedListener,
WifiDppQrCodeScannerFragment.OnScanWifiDppSuccessListener, WifiDppQrCodeScannerFragment.OnScanWifiDppSuccessListener,
WifiDppQrCodeScannerFragment.OnScanZxingWifiFormatSuccessListener { WifiDppQrCodeScannerFragment.OnScanZxingWifiFormatSuccessListener,
WifiDppAddDeviceFragment.OnClickChooseDifferentNetworkListener {
private static final String TAG = "WifiDppConfiguratorActivity"; private static final String TAG = "WifiDppConfiguratorActivity";
public static final String ACTION_CONFIGURATOR_QR_CODE_SCANNER = public static final String ACTION_CONFIGURATOR_QR_CODE_SCANNER =
@@ -66,9 +67,6 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
/** The Wi-Fi network which will be configured */ /** The Wi-Fi network which will be configured */
private WifiNetworkConfig mWifiNetworkConfig; private WifiNetworkConfig mWifiNetworkConfig;
/** The uri from Wi-Fi DPP QR code */
private String mDppUri;
/** The Wi-Fi DPP QR code from intent ACTION_PROCESS_WIFI_DPP_QR_CODE */ /** The Wi-Fi DPP QR code from intent ACTION_PROCESS_WIFI_DPP_QR_CODE */
private WifiQrCode mWifiDppQrCode; private WifiQrCode mWifiDppQrCode;
@@ -117,7 +115,7 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
break; break;
case ACTION_PROCESS_WIFI_DPP_QR_CODE: case ACTION_PROCESS_WIFI_DPP_QR_CODE:
String qrCode = intent.getStringExtra(WifiDppUtils.EXTRA_QR_CODE); String qrCode = intent.getStringExtra(WifiDppUtils.EXTRA_QR_CODE);
mWifiDppQrCode = getValidWiFiDppQrCodeOrNull(qrCode); mWifiDppQrCode = getValidWifiDppQrCodeOrNull(qrCode);
if (mWifiDppQrCode == null) { if (mWifiDppQrCode == null) {
cancelActivity = true; cancelActivity = true;
} else { } else {
@@ -205,7 +203,7 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
fragmentTransaction.commit(); fragmentTransaction.commit();
} }
private WifiQrCode getValidWiFiDppQrCodeOrNull(String qrCode) { private WifiQrCode getValidWifiDppQrCodeOrNull(String qrCode) {
WifiQrCode wifiQrCode; WifiQrCode wifiQrCode;
try { try {
wifiQrCode = new WifiQrCode(qrCode); wifiQrCode = new WifiQrCode(qrCode);
@@ -225,10 +223,6 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
return mWifiNetworkConfig; return mWifiNetworkConfig;
} }
public String getDppUri() {
return mDppUri;
}
public WifiQrCode getWifiDppQrCode() { public WifiQrCode getWifiDppQrCode() {
return mWifiDppQrCode; return mWifiDppQrCode;
} }
@@ -263,17 +257,21 @@ public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
} }
@Override @Override
public void onScanWifiDppSuccess(String uri) { public void onScanWifiDppSuccess(WifiQrCode wifiQrCode) {
mDppUri = uri; mWifiDppQrCode = wifiQrCode;
showAddDeviceFragment(/* addToBackStack */ true); showAddDeviceFragment(/* addToBackStack */ true);
} }
@Override @Override
public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig) { public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig) {
mDppUri = null; // Do nothing, it's impossible to be a configurator without a Wi-Fi DPP QR code
mWifiNetworkConfig = new WifiNetworkConfig(wifiNetworkConfig); }
showAddDeviceFragment(/* addToBackStack */ true); @Override
public void onClickChooseDifferentNetwork() {
mWifiNetworkConfig = null;
showChooseSavedWifiNetworkFragment(/* addToBackStack */ true);
} }
} }

View File

@@ -145,9 +145,10 @@ public class WifiDppEnrolleeActivity extends InstrumentedActivity implements
} }
@Override @Override
public void onScanWifiDppSuccess(String uri) { public void onScanWifiDppSuccess(WifiQrCode wifiQrCode) {
final WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); final WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wifiManager.startDppAsEnrolleeInitiator(uri, /* handler */ null, new DppStatusCallback()); wifiManager.startDppAsEnrolleeInitiator(wifiQrCode.getQrCode(), /* handler */ null,
new DppStatusCallback());
} }
@Override @Override

View File

@@ -100,7 +100,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
// Container Activity must implement this interface // Container Activity must implement this interface
public interface OnScanWifiDppSuccessListener { public interface OnScanWifiDppSuccessListener {
public void onScanWifiDppSuccess(String uri); public void onScanWifiDppSuccess(WifiQrCode wifiQrCode);
} }
OnScanWifiDppSuccessListener mScanWifiDppSuccessListener; OnScanWifiDppSuccessListener mScanWifiDppSuccessListener;
@@ -108,7 +108,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
public interface OnScanZxingWifiFormatSuccessListener { public interface OnScanZxingWifiFormatSuccessListener {
public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig); public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig);
} }
OnScanZxingWifiFormatSuccessListener mScanScanZxingWifiFormatSuccessListener; OnScanZxingWifiFormatSuccessListener mScanZxingWifiFormatSuccessListener;
/** /**
* Configurator container activity of the fragment should create instance with this constructor. * Configurator container activity of the fragment should create instance with this constructor.
@@ -146,13 +146,13 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
super.onAttach(context); super.onAttach(context);
mScanWifiDppSuccessListener = (OnScanWifiDppSuccessListener) context; mScanWifiDppSuccessListener = (OnScanWifiDppSuccessListener) context;
mScanScanZxingWifiFormatSuccessListener = (OnScanZxingWifiFormatSuccessListener) context; mScanZxingWifiFormatSuccessListener = (OnScanZxingWifiFormatSuccessListener) context;
} }
@Override @Override
public void onDetach() { public void onDetach() {
mScanWifiDppSuccessListener = null; mScanWifiDppSuccessListener = null;
mScanScanZxingWifiFormatSuccessListener = null; mScanZxingWifiFormatSuccessListener = null;
super.onDetach(); super.onDetach();
} }
@@ -278,11 +278,11 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
public void handleSuccessfulResult(String qrCode) { public void handleSuccessfulResult(String qrCode) {
switch (mWifiQrCode.getScheme()) { switch (mWifiQrCode.getScheme()) {
case WifiQrCode.SCHEME_DPP: case WifiQrCode.SCHEME_DPP:
handleWifiDpp(qrCode); handleWifiDpp();
break; break;
case WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG: case WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG:
handleZxingWifiFormat(mWifiQrCode.getWifiNetworkConfig()); handleZxingWifiFormat();
break; break;
default: default:
@@ -290,25 +290,22 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
} }
} }
private void handleWifiDpp(String uri) { private void handleWifiDpp() {
destroyCamera(); destroyCamera();
mDecorateView.setFocused(true); mDecorateView.setFocused(true);
final Bundle bundle = new Bundle();
bundle.putString(KEY_PUBLIC_URI, uri);
Message message = mHandler.obtainMessage(MESSAGE_SCAN_WIFI_DPP_SUCCESS); Message message = mHandler.obtainMessage(MESSAGE_SCAN_WIFI_DPP_SUCCESS);
message.setData(bundle); message.obj = new WifiQrCode(mWifiQrCode.getQrCode());
mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL); mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL);
} }
private void handleZxingWifiFormat(WifiNetworkConfig wifiNetworkConfig) { private void handleZxingWifiFormat() {
destroyCamera(); destroyCamera();
mDecorateView.setFocused(true); mDecorateView.setFocused(true);
Message message = mHandler.obtainMessage(MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS); Message message = mHandler.obtainMessage(MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS);
message.obj = wifiNetworkConfig; message.obj = new WifiQrCode(mWifiQrCode.getQrCode()).getWifiNetworkConfig();
mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL); mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL);
} }
@@ -359,17 +356,14 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
if (mScanWifiDppSuccessListener == null) { if (mScanWifiDppSuccessListener == null) {
return; return;
} }
final Bundle bundle = msg.getData(); mScanWifiDppSuccessListener.onScanWifiDppSuccess((WifiQrCode)msg.obj);
final String uri = bundle.getString(KEY_PUBLIC_URI);
mScanWifiDppSuccessListener.onScanWifiDppSuccess(uri);
break; break;
case MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS: case MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS:
if (mScanScanZxingWifiFormatSuccessListener == null) { if (mScanZxingWifiFormatSuccessListener == null) {
return; return;
} }
mScanScanZxingWifiFormatSuccessListener.onScanZxingWifiFormatSuccess( mScanZxingWifiFormatSuccessListener.onScanZxingWifiFormatSuccess(
(WifiNetworkConfig)msg.obj); (WifiNetworkConfig)msg.obj);
break; break;
@@ -381,8 +375,8 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
outState.putBoolean(KEY_IS_CONFIGURATOR_MODE, mIsConfiguratorMode); outState.putBoolean(KEY_IS_CONFIGURATOR_MODE, mIsConfiguratorMode);
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
} }
} }

View File

@@ -20,7 +20,6 @@ import android.content.Intent;
import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.Keep;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import java.util.Arrays; import java.util.Arrays;
@@ -49,7 +48,6 @@ import java.util.regex.Pattern;
* H true Optional. True if the network SSID is hidden. * H true Optional. True if the network SSID is hidden.
* *
*/ */
@Keep
public class WifiQrCode { public class WifiQrCode {
public static final String SCHEME_DPP = "DPP"; public static final String SCHEME_DPP = "DPP";
public static final String SCHEME_ZXING_WIFI_NETWORK_CONFIG = "WIFI"; public static final String SCHEME_ZXING_WIFI_NETWORK_CONFIG = "WIFI";
@@ -86,7 +84,6 @@ public class WifiQrCode {
// Data from parsed ZXing reader library's Wi-Fi Network config format // Data from parsed ZXing reader library's Wi-Fi Network config format
private WifiNetworkConfig mWifiNetworkConfig; private WifiNetworkConfig mWifiNetworkConfig;
@Keep
public WifiQrCode(String qrCode) throws IllegalArgumentException { public WifiQrCode(String qrCode) throws IllegalArgumentException {
if (TextUtils.isEmpty(qrCode)) { if (TextUtils.isEmpty(qrCode)) {
throw new IllegalArgumentException("Empty QR code"); throw new IllegalArgumentException("Empty QR code");
@@ -172,7 +169,6 @@ public class WifiQrCode {
return null; return null;
} }
@Keep
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
protected String removeBackSlash(String input) { protected String removeBackSlash(String input) {
if (input == null) { if (input == null) {
@@ -199,7 +195,6 @@ public class WifiQrCode {
return sb.toString(); return sb.toString();
} }
@Keep
public String getQrCode() { public String getQrCode() {
return mQrCode; return mQrCode;
} }
@@ -210,25 +205,22 @@ public class WifiQrCode {
* SCHEME_DPP for standard Wi-Fi device provision protocol; SCHEME_ZXING_WIFI_NETWORK_CONFIG * SCHEME_DPP for standard Wi-Fi device provision protocol; SCHEME_ZXING_WIFI_NETWORK_CONFIG
* for ZXing reader library' Wi-Fi Network config format * for ZXing reader library' Wi-Fi Network config format
*/ */
@Keep
public String getScheme() { public String getScheme() {
return mScheme; return mScheme;
} }
/** Available when {@code getScheme()} returns SCHEME_DPP */ /** Available when {@code getScheme()} returns SCHEME_DPP */
@Keep @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
public String getPublicKey() { protected String getPublicKey() {
return mPublicKey; return mPublicKey;
} }
/** May be available when {@code getScheme()} returns SCHEME_DPP */ /** May be available when {@code getScheme()} returns SCHEME_DPP */
@Keep
public String getInformation() { public String getInformation() {
return mInformation; return mInformation;
} }
/** Available when {@code getScheme()} returns SCHEME_ZXING_WIFI_NETWORK_CONFIG */ /** Available when {@code getScheme()} returns SCHEME_ZXING_WIFI_NETWORK_CONFIG */
@Keep
public WifiNetworkConfig getWifiNetworkConfig() { public WifiNetworkConfig getWifiNetworkConfig() {
if (mWifiNetworkConfig == null) { if (mWifiNetworkConfig == null) {
return null; return null;

View File

@@ -101,4 +101,12 @@ public class WifiDppConfiguratorActivityTest {
assertThat(activity instanceof WifiDppQrCodeScannerFragment assertThat(activity instanceof WifiDppQrCodeScannerFragment
.OnScanZxingWifiFormatSuccessListener).isEqualTo(true); .OnScanZxingWifiFormatSuccessListener).isEqualTo(true);
} }
@Test
public void testActivity_shouldImplementsOnClickChooseDifferentNetworkCallback() {
WifiDppConfiguratorActivity activity = mActivityRule.getActivity();
assertThat(activity instanceof WifiDppAddDeviceFragment
.OnClickChooseDifferentNetworkListener).isEqualTo(true);
}
} }